mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-03 17:54:06 +00:00
avoid blocking on pagerebuild
Signed-off-by: Bret Curtis <psi29a@gmail.com>
This commit is contained in:
parent
17637c6575
commit
b4af2ac672
@ -1481,9 +1481,15 @@ namespace MWRender
|
||||
{
|
||||
mTerrain->setActiveGrid(grid);
|
||||
}
|
||||
void RenderingManager::pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled)
|
||||
bool RenderingManager::pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled)
|
||||
{
|
||||
if (!ptr.isInCell() || !ptr.getCell()->isExterior())
|
||||
return false;
|
||||
if (mObjectPaging && mObjectPaging->enableObject(type, ptr.getCellRef().getRefNum(), ptr.getRefData().getPosition().asVec3(), enabled))
|
||||
mTerrain->clearCachedViews(ptr.getRefData().getPosition().asVec3());
|
||||
{
|
||||
mTerrain->rebuildViews();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ namespace MWRender
|
||||
|
||||
void setActiveGrid(const osg::Vec4i &grid);
|
||||
|
||||
void pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled);
|
||||
bool pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled);
|
||||
|
||||
private:
|
||||
void updateProjectionMatrix();
|
||||
|
@ -182,10 +182,12 @@ namespace MWWorld
|
||||
{
|
||||
}
|
||||
|
||||
void storeViews(double referenceTime)
|
||||
bool storeViews(double referenceTime)
|
||||
{
|
||||
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size(); ++i)
|
||||
mWorld->storeView(mTerrainViews[i], referenceTime);
|
||||
if (!mWorld->storeView(mTerrainViews[i], referenceTime))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void doWork()
|
||||
@ -244,6 +246,7 @@ namespace MWWorld
|
||||
, mMaxCacheSize(0)
|
||||
, mPreloadInstances(true)
|
||||
, mLastResourceCacheUpdate(0.0)
|
||||
, mStoreViewsFailCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -379,7 +382,17 @@ namespace MWWorld
|
||||
|
||||
if (mTerrainPreloadItem && mTerrainPreloadItem->isDone())
|
||||
{
|
||||
mTerrainPreloadItem->storeViews(timestamp);
|
||||
if (!mTerrainPreloadItem->storeViews(timestamp))
|
||||
{
|
||||
if (++mStoreViewsFailCount > 100)
|
||||
{
|
||||
OSG_ALWAYS << "paging views are rebuilt every frame, please check for faulty enable/disable scripts." << std::endl;
|
||||
mStoreViewsFailCount = 0;
|
||||
}
|
||||
setTerrainPreloadPositions(std::vector<PositionCellGrid>());
|
||||
}
|
||||
else
|
||||
mStoreViewsFailCount = 0;
|
||||
mTerrainPreloadItem = nullptr;
|
||||
}
|
||||
}
|
||||
@ -451,11 +464,31 @@ namespace MWWorld
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(const std::vector<CellPreloader::PositionCellGrid>& container, const std::vector<CellPreloader::PositionCellGrid>& contained)
|
||||
{
|
||||
for (auto pos : contained)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto pos2 : container)
|
||||
{
|
||||
if ((pos.first-pos2.first).length2() < 1 && pos.second == pos2.second)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CellPreloader::setTerrainPreloadPositions(const std::vector<CellPreloader::PositionCellGrid> &positions)
|
||||
{
|
||||
if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone())
|
||||
if (positions.empty())
|
||||
mTerrainPreloadPositions.clear();
|
||||
else if (contains(mTerrainPreloadPositions, positions))
|
||||
return;
|
||||
else if (positions == mTerrainPreloadPositions)
|
||||
if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone())
|
||||
return;
|
||||
else
|
||||
{
|
||||
@ -472,7 +505,6 @@ namespace MWWorld
|
||||
}
|
||||
|
||||
mTerrainPreloadPositions = positions;
|
||||
|
||||
if (!positions.empty())
|
||||
{
|
||||
mTerrainPreloadItem = new TerrainPreloadItem(mTerrainViews, mTerrain, positions);
|
||||
|
@ -88,6 +88,7 @@ namespace MWWorld
|
||||
bool mPreloadInstances;
|
||||
|
||||
double mLastResourceCacheUpdate;
|
||||
int mStoreViewsFailCount;
|
||||
|
||||
struct PreloadEntry
|
||||
{
|
||||
|
@ -1135,6 +1135,11 @@ namespace MWWorld
|
||||
mPreloader->setTerrainPreloadPositions(vec);
|
||||
}
|
||||
|
||||
void Scene::reloadTerrain()
|
||||
{
|
||||
mPreloader->setTerrainPreloadPositions(std::vector<PositionCellGrid>());
|
||||
}
|
||||
|
||||
struct ListFastTravelDestinationsVisitor
|
||||
{
|
||||
ListFastTravelDestinationsVisitor(float preloadDist, const osg::Vec3f& playerPos)
|
||||
|
@ -115,6 +115,7 @@ namespace MWWorld
|
||||
|
||||
void preloadCell(MWWorld::CellStore* cell, bool preloadSurrounding=false);
|
||||
void preloadTerrain(const osg::Vec3f& pos);
|
||||
void reloadTerrain();
|
||||
|
||||
void unloadCell (CellStoreCollection::iterator iter, bool test = false);
|
||||
|
||||
|
@ -817,7 +817,8 @@ namespace MWWorld
|
||||
if (reference.getCellRef().getRefNum().hasContentFile())
|
||||
{
|
||||
int type = mStore.find(Misc::StringUtils::lowerCase(reference.getCellRef().getRefId()));
|
||||
mRendering->pagingEnableObject(type, reference, true);
|
||||
if (mRendering->pagingEnableObject(type, reference, true))
|
||||
mWorldScene->reloadTerrain();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -858,7 +859,8 @@ namespace MWWorld
|
||||
if (reference.getCellRef().getRefNum().hasContentFile())
|
||||
{
|
||||
int type = mStore.find(Misc::StringUtils::lowerCase(reference.getCellRef().getRefId()));
|
||||
mRendering->pagingEnableObject(type, reference, false);
|
||||
if (mRendering->pagingEnableObject(type, reference, false))
|
||||
mWorldScene->reloadTerrain();
|
||||
}
|
||||
|
||||
if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount())
|
||||
|
@ -53,7 +53,6 @@ namespace Terrain
|
||||
virtual bool isSufficientDetail(QuadTreeNode *node, float dist) = 0;
|
||||
};
|
||||
|
||||
class ViewDataMap;
|
||||
class ViewData;
|
||||
|
||||
class QuadTreeNode : public osg::Group
|
||||
|
@ -253,7 +253,6 @@ QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resour
|
||||
|
||||
QuadTreeWorld::~QuadTreeWorld()
|
||||
{
|
||||
mViewDataMap->clear();
|
||||
}
|
||||
|
||||
/// get the level of vertex detail to render this node at, expressed relative to the native resolution of the data set.
|
||||
@ -279,7 +278,7 @@ unsigned int getVertexLod(QuadTreeNode* node, int vertexLodMod)
|
||||
}
|
||||
|
||||
/// get the flags to use for stitching in the index buffer so that chunks of different LOD connect seamlessly
|
||||
unsigned int getLodFlags(QuadTreeNode* node, int ourLod, int vertexLodMod, ViewData* vd)
|
||||
unsigned int getLodFlags(QuadTreeNode* node, int ourLod, int vertexLodMod, const ViewData* vd)
|
||||
{
|
||||
unsigned int lodFlags = 0;
|
||||
for (unsigned int i=0; i<4; ++i)
|
||||
@ -506,7 +505,7 @@ void QuadTreeWorld::enable(bool enabled)
|
||||
|
||||
View* QuadTreeWorld::createView()
|
||||
{
|
||||
return new ViewData;
|
||||
return mViewDataMap->createIndependentView();
|
||||
}
|
||||
|
||||
void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::Vec4i &grid, std::atomic<bool> &abort, std::atomic<int> &progress, int& progressTotal)
|
||||
@ -533,14 +532,9 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::
|
||||
vd->markUnchanged();
|
||||
}
|
||||
|
||||
void QuadTreeWorld::storeView(const View* view, double referenceTime)
|
||||
bool QuadTreeWorld::storeView(const View* view, double referenceTime)
|
||||
{
|
||||
osg::ref_ptr<osg::Object> dummy = new osg::DummyObject;
|
||||
const ViewData* vd = static_cast<const ViewData*>(view);
|
||||
bool needsUpdate = false;
|
||||
ViewData* stored = mViewDataMap->getViewData(dummy, vd->getViewPoint(), vd->getActiveGrid(), needsUpdate);
|
||||
stored->copyFrom(*vd);
|
||||
stored->setLastUsageTimeStamp(referenceTime);
|
||||
return mViewDataMap->storeView(static_cast<const ViewData*>(view), referenceTime);
|
||||
}
|
||||
|
||||
void QuadTreeWorld::reportStats(unsigned int frameNumber, osg::Stats *stats)
|
||||
@ -574,11 +568,9 @@ void QuadTreeWorld::addChunkManager(QuadTreeWorld::ChunkManager* m)
|
||||
mTerrainRoot->setNodeMask(mTerrainRoot->getNodeMask()|m->getNodeMask());
|
||||
}
|
||||
|
||||
void QuadTreeWorld::clearCachedViews(const osg::Vec3f &pos)
|
||||
void QuadTreeWorld::rebuildViews()
|
||||
{
|
||||
//mViewDataMap->clear();
|
||||
osg::Vec3 pos_ = pos / mStorage->getCellWorldSize();
|
||||
mViewDataMap->clearCachedViews(pos_);
|
||||
mViewDataMap->rebuildViews();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ namespace Terrain
|
||||
|
||||
View* createView();
|
||||
void preload(View* view, const osg::Vec3f& eyePoint, const osg::Vec4i &cellgrid, std::atomic<bool>& abort, std::atomic<int>& progress, int& progressRange);
|
||||
void storeView(const View* view, double referenceTime);
|
||||
void clearCachedViews(const osg::Vec3f& pos) override;
|
||||
bool storeView(const View* view, double referenceTime);
|
||||
void rebuildViews() override;
|
||||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats* stats);
|
||||
|
||||
|
@ -10,6 +10,7 @@ ViewData::ViewData()
|
||||
, mLastUsageTimeStamp(0.0)
|
||||
, mChanged(false)
|
||||
, mHasViewPoint(false)
|
||||
, mWorldUpdateRevision(0)
|
||||
{
|
||||
|
||||
}
|
||||
@ -27,6 +28,7 @@ void ViewData::copyFrom(const ViewData& other)
|
||||
mHasViewPoint = other.mHasViewPoint;
|
||||
mViewPoint = other.mViewPoint;
|
||||
mActiveGrid = other.mActiveGrid;
|
||||
mWorldUpdateRevision = other.mWorldUpdateRevision;
|
||||
}
|
||||
|
||||
void ViewData::add(QuadTreeNode *node)
|
||||
@ -93,7 +95,12 @@ void ViewData::clear()
|
||||
mHasViewPoint = false;
|
||||
}
|
||||
|
||||
bool ViewData::contains(QuadTreeNode *node)
|
||||
bool ViewData::suitableToUse(const osg::Vec4i &activeGrid) const
|
||||
{
|
||||
return hasViewPoint() && activeGrid == mActiveGrid && getNumEntries();
|
||||
}
|
||||
|
||||
bool ViewData::contains(QuadTreeNode *node) const
|
||||
{
|
||||
for (unsigned int i=0; i<mNumEntries; ++i)
|
||||
if (mEntries[i].mNode == node)
|
||||
@ -101,18 +108,6 @@ bool ViewData::contains(QuadTreeNode *node)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool intersects(const osg::Vec2f& center, float halfSize, osg::Vec3f pos)
|
||||
{
|
||||
return (pos.x() >= center.x()-halfSize && pos.y() >= center.y()-halfSize && pos.x() <= center.x()+halfSize && pos.y() <= center.y()+halfSize);
|
||||
}
|
||||
|
||||
void ViewData::clearCache(const osg::Vec3f &cellPos)
|
||||
{
|
||||
for (Entry& entry : mEntries)
|
||||
if (entry.mNode && intersects(entry.mNode->getCenter(), entry.mNode->getSize()/2.f, cellPos))
|
||||
entry.mRenderingNode = nullptr;
|
||||
}
|
||||
|
||||
ViewData::Entry::Entry()
|
||||
: mNode(nullptr)
|
||||
, mLodFlags(0)
|
||||
@ -133,86 +128,106 @@ bool ViewData::Entry::set(QuadTreeNode *node)
|
||||
}
|
||||
}
|
||||
|
||||
bool suitable(ViewData* vd, const osg::Vec3f& viewPoint, float& maxDist, const osg::Vec4i& activeGrid)
|
||||
{
|
||||
return vd->hasViewPoint() && (vd->getViewPoint() - viewPoint).length2() < maxDist*maxDist && vd->getActiveGrid() == activeGrid;
|
||||
}
|
||||
|
||||
ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPoint, const osg::Vec4i &activeGrid, bool& needsUpdate)
|
||||
{
|
||||
Map::const_iterator found = mViews.find(viewer);
|
||||
ViewerMap::const_iterator found = mViewers.find(viewer);
|
||||
ViewData* vd = nullptr;
|
||||
if (found == mViews.end())
|
||||
if (found == mViewers.end())
|
||||
{
|
||||
vd = createOrReuseView();
|
||||
mViews[viewer] = vd;
|
||||
mViewers[viewer] = vd;
|
||||
}
|
||||
else
|
||||
vd = found->second;
|
||||
needsUpdate = false;
|
||||
|
||||
if (!suitable(vd, viewPoint, mReuseDistance, activeGrid))
|
||||
if (!(vd->suitableToUse(activeGrid) && (vd->getViewPoint()-viewPoint).length2() < mReuseDistance*mReuseDistance && vd->getWorldUpdateRevision() >= mWorldUpdateRevision))
|
||||
{
|
||||
for (Map::const_iterator other = mViews.begin(); other != mViews.end(); ++other)
|
||||
float shortestDist = std::numeric_limits<float>::max();
|
||||
const ViewData* mostSuitableView = nullptr;
|
||||
for (const ViewData& other : mViewVector)
|
||||
{
|
||||
if (suitable(other->second, viewPoint, mReuseDistance, activeGrid) && other->second->getNumEntries())
|
||||
if (other.suitableToUse(activeGrid) && other.getWorldUpdateRevision() >= mWorldUpdateRevision)
|
||||
{
|
||||
vd->copyFrom(*other->second);
|
||||
needsUpdate = false;
|
||||
return vd;
|
||||
float dist = (viewPoint-other.getViewPoint()).length2();
|
||||
if (dist < shortestDist)
|
||||
{
|
||||
shortestDist = dist;
|
||||
mostSuitableView = &other;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mostSuitableView && mostSuitableView != vd)
|
||||
{
|
||||
vd->copyFrom(*mostSuitableView);
|
||||
return vd;
|
||||
}
|
||||
}
|
||||
if (!vd->suitableToUse(activeGrid))
|
||||
{
|
||||
vd->setViewPoint(viewPoint);
|
||||
vd->setActiveGrid(activeGrid);
|
||||
needsUpdate = true;
|
||||
}
|
||||
else
|
||||
needsUpdate = false;
|
||||
|
||||
return vd;
|
||||
}
|
||||
|
||||
bool ViewDataMap::storeView(const ViewData* view, double referenceTime)
|
||||
{
|
||||
if (view->getWorldUpdateRevision() < mWorldUpdateRevision)
|
||||
return false;
|
||||
ViewData* store = createOrReuseView();
|
||||
store->copyFrom(*view);
|
||||
store->setLastUsageTimeStamp(referenceTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
ViewData *ViewDataMap::createOrReuseView()
|
||||
{
|
||||
ViewData* vd = nullptr;
|
||||
if (mUnusedViews.size())
|
||||
{
|
||||
ViewData* vd = mUnusedViews.front();
|
||||
vd = mUnusedViews.front();
|
||||
mUnusedViews.pop_front();
|
||||
return vd;
|
||||
}
|
||||
else
|
||||
{
|
||||
mViewVector.push_back(ViewData());
|
||||
return &mViewVector.back();
|
||||
vd = &mViewVector.back();
|
||||
}
|
||||
vd->setWorldUpdateRevision(mWorldUpdateRevision);
|
||||
return vd;
|
||||
}
|
||||
|
||||
ViewData *ViewDataMap::createIndependentView() const
|
||||
{
|
||||
ViewData* vd = new ViewData;
|
||||
vd->setWorldUpdateRevision(mWorldUpdateRevision);
|
||||
return vd;
|
||||
}
|
||||
|
||||
void ViewDataMap::clearUnusedViews(double referenceTime)
|
||||
{
|
||||
for (Map::iterator it = mViews.begin(); it != mViews.end(); )
|
||||
for (ViewerMap::iterator it = mViewers.begin(); it != mViewers.end(); )
|
||||
{
|
||||
ViewData* vd = it->second;
|
||||
if (vd->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
|
||||
{
|
||||
vd->clear();
|
||||
mUnusedViews.push_back(vd);
|
||||
mViews.erase(it++);
|
||||
}
|
||||
if (it->second->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
|
||||
mViewers.erase(it++);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
for (ViewData& vd : mViewVector)
|
||||
{
|
||||
if (vd.getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
|
||||
{
|
||||
vd.clear();
|
||||
mUnusedViews.push_back(&vd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ViewDataMap::clearCachedViews(const osg::Vec3f &cellPos)
|
||||
void ViewDataMap::rebuildViews()
|
||||
{
|
||||
for (auto pair : mViews)
|
||||
pair.second->clearCache(cellPos);
|
||||
}
|
||||
|
||||
void ViewDataMap::clear()
|
||||
{
|
||||
mViews.clear();
|
||||
mUnusedViews.clear();
|
||||
mViewVector.clear();
|
||||
++mWorldUpdateRevision;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,10 +23,11 @@ namespace Terrain
|
||||
|
||||
void reset();
|
||||
|
||||
void clear();
|
||||
void clearCache(const osg::Vec3f &cellPos);
|
||||
bool suitableToUse(const osg::Vec4i& activeGrid) const;
|
||||
|
||||
bool contains(QuadTreeNode* node);
|
||||
void clear();
|
||||
|
||||
bool contains(QuadTreeNode* node) const;
|
||||
|
||||
void copyFrom(const ViewData& other);
|
||||
|
||||
@ -61,6 +62,9 @@ namespace Terrain
|
||||
void setActiveGrid(const osg::Vec4i &grid) { if (grid != mActiveGrid) {mActiveGrid = grid;mEntries.clear();mNumEntries=0;} }
|
||||
const osg::Vec4i &getActiveGrid() const { return mActiveGrid;}
|
||||
|
||||
unsigned int getWorldUpdateRevision() const { return mWorldUpdateRevision; }
|
||||
void setWorldUpdateRevision(int updateRevision) { mWorldUpdateRevision = updateRevision; }
|
||||
|
||||
private:
|
||||
std::vector<Entry> mEntries;
|
||||
unsigned int mNumEntries;
|
||||
@ -69,35 +73,39 @@ namespace Terrain
|
||||
osg::Vec3f mViewPoint;
|
||||
bool mHasViewPoint;
|
||||
osg::Vec4i mActiveGrid;
|
||||
unsigned int mWorldUpdateRevision;
|
||||
};
|
||||
|
||||
class ViewDataMap : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
ViewDataMap()
|
||||
: mReuseDistance(300) // large value should be safe because the visibility of each node is still updated individually for each camera even if the base view was reused.
|
||||
: mReuseDistance(150) // large value should be safe because the visibility of each node is still updated individually for each camera even if the base view was reused.
|
||||
// this value also serves as a threshold for when a newly loaded LOD gets unloaded again so that if you hover around an LOD transition point the LODs won't keep loading and unloading all the time.
|
||||
, mExpiryDelay(1.f)
|
||||
, mWorldUpdateRevision(0)
|
||||
{}
|
||||
|
||||
ViewData* getViewData(osg::Object* viewer, const osg::Vec3f& viewPoint, const osg::Vec4i &activeGrid, bool& needsUpdate);
|
||||
|
||||
ViewData* createOrReuseView();
|
||||
ViewData* createIndependentView() const;
|
||||
|
||||
void clearUnusedViews(double referenceTime);
|
||||
void clearCachedViews(const osg::Vec3f &cellPos);
|
||||
|
||||
void clear();
|
||||
void rebuildViews();
|
||||
bool storeView(const ViewData* view, double referenceTime);
|
||||
|
||||
private:
|
||||
std::list<ViewData> mViewVector;
|
||||
|
||||
typedef std::map<osg::ref_ptr<osg::Object>, ViewData*> Map;
|
||||
Map mViews;
|
||||
typedef std::map<osg::ref_ptr<osg::Object>, ViewData*> ViewerMap;
|
||||
ViewerMap mViewers;
|
||||
|
||||
float mReuseDistance;
|
||||
float mExpiryDelay; // time in seconds for unused view to be removed
|
||||
|
||||
unsigned int mWorldUpdateRevision;
|
||||
|
||||
std::deque<ViewData*> mUnusedViews;
|
||||
};
|
||||
|
||||
|
@ -151,9 +151,9 @@ namespace Terrain
|
||||
|
||||
/// Store a preloaded view into the cache with the intent that the next rendering traversal can use it.
|
||||
/// @note Not thread safe.
|
||||
virtual void storeView(const View* view, double referenceTime) {}
|
||||
virtual bool storeView(const View* view, double referenceTime) {return true;}
|
||||
|
||||
virtual void clearCachedViews(const osg::Vec3f& pos) {}
|
||||
virtual void rebuildViews() {}
|
||||
|
||||
virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) {}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user