avoid pagerebuild when reloading a same save

Signed-off-by: Bret Curtis <psi29a@gmail.com>
pull/578/head
bzzt lost a hitlab login 5 years ago committed by Bret Curtis
parent 6fa12a6eb8
commit b27b76e325

@ -339,6 +339,7 @@ namespace MWRender
ObjectPaging::ObjectPaging(Resource::SceneManager* sceneManager) ObjectPaging::ObjectPaging(Resource::SceneManager* sceneManager)
: GenericResourceManager<ChunkId>(nullptr) : GenericResourceManager<ChunkId>(nullptr)
, mSceneManager(sceneManager) , mSceneManager(sceneManager)
, mRefTrackerLocked(false)
{ {
mActiveGrid = Settings::Manager::getBool("object paging active grid", "Terrain"); mActiveGrid = Settings::Manager::getBool("object paging active grid", "Terrain");
mDebugBatches = Settings::Manager::getBool("object paging debug batches", "Terrain"); mDebugBatches = Settings::Manager::getBool("object paging debug batches", "Terrain");
@ -403,9 +404,9 @@ namespace MWRender
} }
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mDisabledMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
if (activeGrid) if (activeGrid)
for (auto ref : mBlacklist) for (auto ref : getRefTracker().mBlacklist)
refs.erase(ref); refs.erase(ref);
} }
@ -489,8 +490,8 @@ namespace MWRender
} }
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mDisabledMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
if (mDisabled.count(pair.first)) if (getRefTracker().mDisabled.count(pair.first))
continue; continue;
} }
@ -683,14 +684,16 @@ namespace MWRender
return false; return false;
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mDisabledMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
if (enabled && !mDisabled.erase(refnum)) return false; if (enabled && !getWritableRefTracker().mDisabled.erase(refnum)) return false;
if (!enabled && !mDisabled.insert(refnum).second) return false; if (!enabled && !getWritableRefTracker().mDisabled.insert(refnum).second) return false;
if (mRefTrackerLocked) return false;
} }
ClearCacheFunctor ccf; ClearCacheFunctor ccf;
ccf.mPosition = pos; ccf.mPosition = pos;
mCache->call(ccf); mCache->call(ccf);
if (ccf.mToClear.empty()) return false;
for (auto chunk : ccf.mToClear) for (auto chunk : ccf.mToClear)
mCache->removeFromObjectCache(chunk); mCache->removeFromObjectCache(chunk);
return true; return true;
@ -702,8 +705,9 @@ namespace MWRender
return false; return false;
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mDisabledMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
if (!mBlacklist.insert(refnum).second) return false; if (!getWritableRefTracker().mBlacklist.insert(refnum).second) return false;
if (mRefTrackerLocked) return false;
} }
ClearCacheFunctor ccf; ClearCacheFunctor ccf;
@ -719,12 +723,25 @@ namespace MWRender
void ObjectPaging::clear() void ObjectPaging::clear()
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
mRefTrackerNew.mDisabled.clear();
mRefTrackerNew.mBlacklist.clear();
mRefTrackerLocked = true;
}
bool ObjectPaging::unlockCache()
{
if (!mRefTrackerLocked) return false;
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mDisabledMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mRefTrackerMutex);
mDisabled.clear(); mRefTrackerLocked = false;
mBlacklist.clear(); if (mRefTracker == mRefTrackerNew)
return false;
else
mRefTracker = mRefTrackerNew;
} }
mCache->clear(); mCache->clear();
return true;
} }
struct GetRefnumsFunctor struct GetRefnumsFunctor

@ -41,6 +41,10 @@ namespace MWRender
void clear(); void clear();
/// Must be called after clear() before rendering starts.
/// @return true if view needs rebuild
bool unlockCache();
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
void getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out); void getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out);
@ -54,9 +58,19 @@ namespace MWRender
float mMinSizeMergeFactor; float mMinSizeMergeFactor;
float mMinSizeCostMultiplier; float mMinSizeCostMultiplier;
OpenThreads::Mutex mDisabledMutex; OpenThreads::Mutex mRefTrackerMutex;
std::set<ESM::RefNum> mDisabled; struct RefTracker
std::set<ESM::RefNum> mBlacklist; {
std::set<ESM::RefNum> mDisabled;
std::set<ESM::RefNum> mBlacklist;
bool operator==(const RefTracker&other) { return mDisabled == other.mDisabled && mBlacklist == other.mBlacklist; }
};
RefTracker mRefTracker;
RefTracker mRefTrackerNew;
bool mRefTrackerLocked;
const RefTracker& getRefTracker() const { return mRefTracker; }
RefTracker& getWritableRefTracker() { return mRefTrackerLocked ? mRefTrackerNew : mRefTracker; }
OpenThreads::Mutex mSizeCacheMutex; OpenThreads::Mutex mSizeCacheMutex;
typedef std::map<ESM::RefNum, float> SizeCache; typedef std::map<ESM::RefNum, float> SizeCache;

@ -1511,6 +1511,15 @@ namespace MWRender
if (mObjectPaging->blacklistObject(type, refnum, ptr.getCellRef().getPosition().asVec3())) if (mObjectPaging->blacklistObject(type, refnum, ptr.getCellRef().getPosition().asVec3()))
mTerrain->rebuildViews(); mTerrain->rebuildViews();
} }
bool RenderingManager::pagingUnlockCache()
{
if (mObjectPaging && mObjectPaging->unlockCache())
{
mTerrain->rebuildViews();
return true;
}
return false;
}
void RenderingManager::getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out) void RenderingManager::getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out)
{ {
if (mObjectPaging) if (mObjectPaging)

@ -244,6 +244,7 @@ namespace MWRender
bool pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled); bool pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled);
void pagingBlacklistObject(int type, const MWWorld::ConstPtr &ptr); void pagingBlacklistObject(int type, const MWWorld::ConstPtr &ptr);
bool pagingUnlockCache();
void getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out); void getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out);
private: private:

@ -419,36 +419,44 @@ namespace MWWorld
mUnrefQueue = unrefQueue; mUnrefQueue = unrefQueue;
} }
bool CellPreloader::getTerrainPreloadInProgress(int& progress, int& progressRange, double timestamp) bool CellPreloader::syncTerrainLoad(const std::vector<CellPreloader::PositionCellGrid> &positions, int& progress, int& progressRange, double timestamp)
{ {
if (!mTerrainPreloadItem) if (!mTerrainPreloadItem)
return false; return true;
else if (mTerrainPreloadItem->isDone()) else if (mTerrainPreloadItem->isDone())
{ {
mTerrainPreloadItem->storeViews(timestamp); if (mTerrainPreloadItem->storeViews(timestamp))
mTerrainPreloadItem = nullptr; {
return false; mTerrainPreloadItem = nullptr;
return true;
}
else
{
setTerrainPreloadPositions(std::vector<CellPreloader::PositionCellGrid>());
setTerrainPreloadPositions(positions);
return false;
}
} }
else else
{ {
progress = mTerrainPreloadItem->getProgress(); progress = mTerrainPreloadItem->getProgress();
progressRange = mTerrainPreloadItem->getProgressRange(); progressRange = mTerrainPreloadItem->getProgressRange();
return !progress || progress < progressRange; return false;
} }
} }
void CellPreloader::abortTerrainPreloadExcept(const CellPreloader::PositionCellGrid& exceptPos) void CellPreloader::abortTerrainPreloadExcept(const CellPreloader::PositionCellGrid *exceptPos)
{ {
const float resetThreshold = ESM::Land::REAL_SIZE;
for (auto pos : mTerrainPreloadPositions)
if (exceptPos && (pos.first-exceptPos->first).length2() < resetThreshold*resetThreshold && pos.second == exceptPos->second)
return;
if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone()) if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone())
{ {
const float resetThreshold = ESM::Land::REAL_SIZE;
for (auto pos : mTerrainPreloadPositions)
if ((pos.first-exceptPos.first).length2() < resetThreshold*resetThreshold && pos.second == exceptPos.second)
return;
mTerrainPreloadItem->abort(); mTerrainPreloadItem->abort();
mTerrainPreloadItem->waitTillDone(); mTerrainPreloadItem->waitTillDone();
mTerrainPreloadItem = nullptr;
} }
setTerrainPreloadPositions(std::vector<CellPreloader::PositionCellGrid>());
} }
bool contains(const std::vector<CellPreloader::PositionCellGrid>& container, const std::vector<CellPreloader::PositionCellGrid>& contained) bool contains(const std::vector<CellPreloader::PositionCellGrid>& container, const std::vector<CellPreloader::PositionCellGrid>& contained)

@ -72,8 +72,8 @@ namespace MWWorld
typedef std::pair<osg::Vec3f, osg::Vec4i> PositionCellGrid; typedef std::pair<osg::Vec3f, osg::Vec4i> PositionCellGrid;
void setTerrainPreloadPositions(const std::vector<PositionCellGrid>& positions); void setTerrainPreloadPositions(const std::vector<PositionCellGrid>& positions);
bool getTerrainPreloadInProgress(int& progress, int& progressRange, double timestamp); bool syncTerrainLoad(const std::vector<CellPreloader::PositionCellGrid> &positions, int& progress, int& progressRange, double timestamp);
void abortTerrainPreloadExcept(const PositionCellGrid &exceptPos); void abortTerrainPreloadExcept(const PositionCellGrid *exceptPos);
private: private:
Resource::ResourceSystem* mResourceSystem; Resource::ResourceSystem* mResourceSystem;

@ -510,13 +510,10 @@ namespace MWWorld
osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter); osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter);
if (newCell != mCurrentGridCenter) if (newCell != mCurrentGridCenter)
{ changeCellGrid(pos, newCell.x(), newCell.y());
preloadTerrain(pos);
changeCellGrid(newCell.x(), newCell.y());
}
} }
void Scene::changeCellGrid (int playerCellX, int playerCellY, bool changeEvent) void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent)
{ {
CellStoreCollection::iterator active = mActiveCells.begin(); CellStoreCollection::iterator active = mActiveCells.begin();
while (active!=mActiveCells.end()) while (active!=mActiveCells.end())
@ -538,8 +535,8 @@ namespace MWWorld
osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter); osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter);
mRendering.setActiveGrid(newGrid); mRendering.setActiveGrid(newGrid);
preloadTerrain(pos, true);
mPagedRefs.clear(); mPagedRefs.clear();
checkTerrainLoaded();
mRendering.getPagedRefnums(newGrid, mPagedRefs); mRendering.getPagedRefnums(newGrid, mPagedRefs);
std::size_t refsToLoad = 0; std::size_t refsToLoad = 0;
@ -867,9 +864,7 @@ namespace MWWorld
if (changeEvent) if (changeEvent)
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5);
preloadTerrain(position.asVec3()); changeCellGrid(position.asVec3(), x, y, changeEvent);
checkTerrainLoaded();
changeCellGrid(x, y, changeEvent);
CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y);
changePlayerCell(current, position, adjustPlayerPos); changePlayerCell(current, position, adjustPlayerPos);
@ -878,29 +873,6 @@ namespace MWWorld
MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5);
} }
void Scene::checkTerrainLoaded()
{
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(loadingListener);
int progress = 0, initialProgress = -1, progressRange = 0;
while (mPreloader->getTerrainPreloadInProgress(progress, progressRange, mRendering.getReferenceTime()))
{
if (initialProgress == -1)
{
loadingListener->setLabel("#{sLoadingMessage4}");
initialProgress = progress;
}
if (progress)
{
loadingListener->setProgressRange(std::max(0, progressRange-initialProgress));
loadingListener->setProgress(progress-initialProgress);
}
else
loadingListener->setProgress(0);
OpenThreads::Thread::microSleep(5000);
}
}
CellStore* Scene::getCurrentCell () CellStore* Scene::getCurrentCell ()
{ {
return mCurrentCell; return mCurrentCell;
@ -1145,12 +1117,36 @@ namespace MWWorld
mPreloader->preload(cell, mRendering.getReferenceTime()); mPreloader->preload(cell, mRendering.getReferenceTime());
} }
void Scene::preloadTerrain(const osg::Vec3f &pos) void Scene::preloadTerrain(const osg::Vec3f &pos, bool sync)
{ {
std::vector<PositionCellGrid> vec; std::vector<PositionCellGrid> vec;
vec.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); vec.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos)));
mPreloader->abortTerrainPreloadExcept(vec[0]); if (sync && mRendering.pagingUnlockCache())
mPreloader->abortTerrainPreloadExcept(nullptr);
else
mPreloader->abortTerrainPreloadExcept(&vec[0]);
mPreloader->setTerrainPreloadPositions(vec); mPreloader->setTerrainPreloadPositions(vec);
if (!sync) return;
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(loadingListener);
int progress = 0, initialProgress = -1, progressRange = 0;
while (!mPreloader->syncTerrainLoad(vec, progress, progressRange, mRendering.getReferenceTime()))
{
if (initialProgress == -1)
{
loadingListener->setLabel("#{sLoadingMessage4}");
initialProgress = progress;
}
if (progress)
{
loadingListener->setProgressRange(std::max(0, progressRange-initialProgress));
loadingListener->setProgress(progress-initialProgress);
}
else
loadingListener->setProgress(0);
OpenThreads::Thread::microSleep(5000);
}
} }
void Scene::reloadTerrain() void Scene::reloadTerrain()

@ -93,7 +93,7 @@ namespace MWWorld
osg::Vec2i mCurrentGridCenter; osg::Vec2i mCurrentGridCenter;
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
void changeCellGrid (int playerCellX, int playerCellY, bool changeEvent = true); void changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent = true);
typedef std::pair<osg::Vec3f, osg::Vec4i> PositionCellGrid; typedef std::pair<osg::Vec3f, osg::Vec4i> PositionCellGrid;
@ -102,8 +102,6 @@ namespace MWWorld
void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos); void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos);
void preloadFastTravelDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos, std::vector<PositionCellGrid>& exteriorPositions); void preloadFastTravelDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos, std::vector<PositionCellGrid>& exteriorPositions);
void checkTerrainLoaded();
osg::Vec4i gridCenterToBounds(const osg::Vec2i &centerCell) const; osg::Vec4i gridCenterToBounds(const osg::Vec2i &centerCell) const;
osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const; osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const;
@ -115,7 +113,7 @@ namespace MWWorld
~Scene(); ~Scene();
void preloadCell(MWWorld::CellStore* cell, bool preloadSurrounding=false); void preloadCell(MWWorld::CellStore* cell, bool preloadSurrounding=false);
void preloadTerrain(const osg::Vec3f& pos); void preloadTerrain(const osg::Vec3f& pos, bool sync=false);
void reloadTerrain(); void reloadTerrain();
void unloadCell (CellStoreCollection::iterator iter, bool test = false); void unloadCell (CellStoreCollection::iterator iter, bool test = false);

Loading…
Cancel
Save