From b27b76e32582601412da380eef273619a62cfe4b Mon Sep 17 00:00:00 2001 From: bzzt lost a hitlab login Date: Tue, 12 May 2020 13:37:00 +0000 Subject: [PATCH] avoid pagerebuild when reloading a same save Signed-off-by: Bret Curtis --- apps/openmw/mwrender/objectpaging.cpp | 41 ++++++++++----- apps/openmw/mwrender/objectpaging.hpp | 20 +++++-- apps/openmw/mwrender/renderingmanager.cpp | 9 ++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwworld/cellpreloader.cpp | 32 +++++++----- apps/openmw/mwworld/cellpreloader.hpp | 4 +- apps/openmw/mwworld/scene.cpp | 64 +++++++++++------------ apps/openmw/mwworld/scene.hpp | 6 +-- 8 files changed, 110 insertions(+), 67 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 365e8ec91..c3a90da80 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -339,6 +339,7 @@ namespace MWRender ObjectPaging::ObjectPaging(Resource::SceneManager* sceneManager) : GenericResourceManager(nullptr) , mSceneManager(sceneManager) + , mRefTrackerLocked(false) { mActiveGrid = Settings::Manager::getBool("object paging active grid", "Terrain"); mDebugBatches = Settings::Manager::getBool("object paging debug batches", "Terrain"); @@ -403,9 +404,9 @@ namespace MWRender } { - OpenThreads::ScopedLock lock(mDisabledMutex); + OpenThreads::ScopedLock lock(mRefTrackerMutex); if (activeGrid) - for (auto ref : mBlacklist) + for (auto ref : getRefTracker().mBlacklist) refs.erase(ref); } @@ -489,8 +490,8 @@ namespace MWRender } { - OpenThreads::ScopedLock lock(mDisabledMutex); - if (mDisabled.count(pair.first)) + OpenThreads::ScopedLock lock(mRefTrackerMutex); + if (getRefTracker().mDisabled.count(pair.first)) continue; } @@ -683,14 +684,16 @@ namespace MWRender return false; { - OpenThreads::ScopedLock lock(mDisabledMutex); - if (enabled && !mDisabled.erase(refnum)) return false; - if (!enabled && !mDisabled.insert(refnum).second) return false; + OpenThreads::ScopedLock lock(mRefTrackerMutex); + if (enabled && !getWritableRefTracker().mDisabled.erase(refnum)) return false; + if (!enabled && !getWritableRefTracker().mDisabled.insert(refnum).second) return false; + if (mRefTrackerLocked) return false; } ClearCacheFunctor ccf; ccf.mPosition = pos; mCache->call(ccf); + if (ccf.mToClear.empty()) return false; for (auto chunk : ccf.mToClear) mCache->removeFromObjectCache(chunk); return true; @@ -702,8 +705,9 @@ namespace MWRender return false; { - OpenThreads::ScopedLock lock(mDisabledMutex); - if (!mBlacklist.insert(refnum).second) return false; + OpenThreads::ScopedLock lock(mRefTrackerMutex); + if (!getWritableRefTracker().mBlacklist.insert(refnum).second) return false; + if (mRefTrackerLocked) return false; } ClearCacheFunctor ccf; @@ -719,12 +723,25 @@ namespace MWRender void ObjectPaging::clear() { + OpenThreads::ScopedLock lock(mRefTrackerMutex); + mRefTrackerNew.mDisabled.clear(); + mRefTrackerNew.mBlacklist.clear(); + mRefTrackerLocked = true; + } + + bool ObjectPaging::unlockCache() + { + if (!mRefTrackerLocked) return false; { - OpenThreads::ScopedLock lock(mDisabledMutex); - mDisabled.clear(); - mBlacklist.clear(); + OpenThreads::ScopedLock lock(mRefTrackerMutex); + mRefTrackerLocked = false; + if (mRefTracker == mRefTrackerNew) + return false; + else + mRefTracker = mRefTrackerNew; } mCache->clear(); + return true; } struct GetRefnumsFunctor diff --git a/apps/openmw/mwrender/objectpaging.hpp b/apps/openmw/mwrender/objectpaging.hpp index 03d9ccfad..c79dd6e06 100644 --- a/apps/openmw/mwrender/objectpaging.hpp +++ b/apps/openmw/mwrender/objectpaging.hpp @@ -41,6 +41,10 @@ namespace MWRender 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 getPagedRefnums(const osg::Vec4i &activeGrid, std::set &out); @@ -54,9 +58,19 @@ namespace MWRender float mMinSizeMergeFactor; float mMinSizeCostMultiplier; - OpenThreads::Mutex mDisabledMutex; - std::set mDisabled; - std::set mBlacklist; + OpenThreads::Mutex mRefTrackerMutex; + struct RefTracker + { + std::set mDisabled; + std::set 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; typedef std::map SizeCache; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 30e63e56e..99f3e25ac 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1511,6 +1511,15 @@ namespace MWRender if (mObjectPaging->blacklistObject(type, refnum, ptr.getCellRef().getPosition().asVec3())) mTerrain->rebuildViews(); } + bool RenderingManager::pagingUnlockCache() + { + if (mObjectPaging && mObjectPaging->unlockCache()) + { + mTerrain->rebuildViews(); + return true; + } + return false; + } void RenderingManager::getPagedRefnums(const osg::Vec4i &activeGrid, std::set &out) { if (mObjectPaging) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b18d2caf1..db4788970 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -244,6 +244,7 @@ namespace MWRender bool pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled); void pagingBlacklistObject(int type, const MWWorld::ConstPtr &ptr); + bool pagingUnlockCache(); void getPagedRefnums(const osg::Vec4i &activeGrid, std::set &out); private: diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 872a29e89..bee6a957d 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -419,36 +419,44 @@ namespace MWWorld mUnrefQueue = unrefQueue; } - bool CellPreloader::getTerrainPreloadInProgress(int& progress, int& progressRange, double timestamp) + bool CellPreloader::syncTerrainLoad(const std::vector &positions, int& progress, int& progressRange, double timestamp) { if (!mTerrainPreloadItem) - return false; + return true; else if (mTerrainPreloadItem->isDone()) { - mTerrainPreloadItem->storeViews(timestamp); - mTerrainPreloadItem = nullptr; - return false; + if (mTerrainPreloadItem->storeViews(timestamp)) + { + mTerrainPreloadItem = nullptr; + return true; + } + else + { + setTerrainPreloadPositions(std::vector()); + setTerrainPreloadPositions(positions); + return false; + } } else { progress = mTerrainPreloadItem->getProgress(); 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()) { - 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->waitTillDone(); - mTerrainPreloadItem = nullptr; } + setTerrainPreloadPositions(std::vector()); } bool contains(const std::vector& container, const std::vector& contained) diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index 98e173f17..e719f2e60 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -72,8 +72,8 @@ namespace MWWorld typedef std::pair PositionCellGrid; void setTerrainPreloadPositions(const std::vector& positions); - bool getTerrainPreloadInProgress(int& progress, int& progressRange, double timestamp); - void abortTerrainPreloadExcept(const PositionCellGrid &exceptPos); + bool syncTerrainLoad(const std::vector &positions, int& progress, int& progressRange, double timestamp); + void abortTerrainPreloadExcept(const PositionCellGrid *exceptPos); private: Resource::ResourceSystem* mResourceSystem; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d2b31a855..53ddaf08c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -510,13 +510,10 @@ namespace MWWorld osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter); if (newCell != mCurrentGridCenter) - { - preloadTerrain(pos); - changeCellGrid(newCell.x(), newCell.y()); - } + changeCellGrid(pos, 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(); while (active!=mActiveCells.end()) @@ -538,8 +535,8 @@ namespace MWWorld osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter); mRendering.setActiveGrid(newGrid); + preloadTerrain(pos, true); mPagedRefs.clear(); - checkTerrainLoaded(); mRendering.getPagedRefnums(newGrid, mPagedRefs); std::size_t refsToLoad = 0; @@ -867,9 +864,7 @@ namespace MWWorld if (changeEvent) MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); - preloadTerrain(position.asVec3()); - checkTerrainLoaded(); - changeCellGrid(x, y, changeEvent); + changeCellGrid(position.asVec3(), x, y, changeEvent); CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); changePlayerCell(current, position, adjustPlayerPos); @@ -878,29 +873,6 @@ namespace MWWorld 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 () { return mCurrentCell; @@ -1145,12 +1117,36 @@ namespace MWWorld mPreloader->preload(cell, mRendering.getReferenceTime()); } - void Scene::preloadTerrain(const osg::Vec3f &pos) + void Scene::preloadTerrain(const osg::Vec3f &pos, bool sync) { std::vector vec; 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); + 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() diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 227bb7b31..b9a39779d 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -93,7 +93,7 @@ namespace MWWorld osg::Vec2i mCurrentGridCenter; // 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 PositionCellGrid; @@ -102,8 +102,6 @@ namespace MWWorld void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos); void preloadFastTravelDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos, std::vector& exteriorPositions); - void checkTerrainLoaded(); - osg::Vec4i gridCenterToBounds(const osg::Vec2i ¢erCell) const; osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const; @@ -115,7 +113,7 @@ namespace MWWorld ~Scene(); 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 unloadCell (CellStoreCollection::iterator iter, bool test = false);