From a46593fa7418caaa078656fd89a565b016f789c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Feb 2017 01:08:07 +0100 Subject: [PATCH] Add PreloadItem::abort() to avoid no longer required cells from blocking the work thread --- apps/openmw/mwworld/cellpreloader.cpp | 23 +++++++++++++++++++++++ components/sceneutil/workqueue.hpp | 3 +++ 2 files changed, 26 insertions(+) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index d76e5ddcb..3608699fb 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -55,6 +55,7 @@ namespace MWWorld , mKeyframeManager(keyframeManager) , mTerrain(terrain) , mPreloadInstances(preloadInstances) + , mAbort(false) { ListModelsVisitor visitor (mMeshes); if (cell->getState() == MWWorld::CellStore::State_Loaded) @@ -76,6 +77,11 @@ namespace MWWorld } } + virtual void abort() + { + mAbort = true; + } + /// Preload work to be called from the worker thread. virtual void doWork() { @@ -92,6 +98,9 @@ namespace MWWorld for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) { + if (mAbort) + break; + try { std::string mesh = *it; @@ -144,6 +153,8 @@ namespace MWWorld Terrain::World* mTerrain; bool mPreloadInstances; + volatile bool mAbort; + // 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 > mPreloadedObjects; }; @@ -187,7 +198,10 @@ namespace MWWorld CellPreloader::~CellPreloader() { for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();++it) + { + it->second.mWorkItem->abort(); it->second.mWorkItem->waitTillDone(); + } mPreloadCells.clear(); } @@ -228,7 +242,10 @@ namespace MWWorld } if (oldestTimestamp + threshold < timestamp) + { + oldestCell->second.mWorkItem->abort(); mPreloadCells.erase(oldestCell); + } else return; } @@ -246,7 +263,10 @@ namespace MWWorld { // do the deletion in the background thread if (found->second.mWorkItem) + { + found->second.mWorkItem->abort(); mUnrefQueue->push(mPreloadCells[cell].mWorkItem); + } mPreloadCells.erase(found); } @@ -257,7 +277,10 @@ namespace MWWorld for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();) { if (mPreloadCells.size() >= mMinCacheSize && it->second.mTimeStamp < timestamp - mExpiryDelay) + { + it->second.mWorkItem->abort(); mPreloadCells.erase(it++); + } else ++it; } diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp index e7b0151dd..1b0e30be9 100644 --- a/components/sceneutil/workqueue.hpp +++ b/components/sceneutil/workqueue.hpp @@ -31,6 +31,9 @@ namespace SceneUtil /// Internal use by the WorkQueue. void signalDone(); + /// Set abort flag in order to return from doWork() as soon as possible. May not be respected by all WorkItems. + virtual void abort() {} + protected: OpenThreads::Atomic mDone; OpenThreads::Mutex mMutex;