mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:53:51 +00:00
Store preloaded terrain view in the main thread
This commit is contained in:
parent
63ab7345be
commit
489e5c6cce
7 changed files with 88 additions and 49 deletions
|
@ -167,6 +167,44 @@ namespace MWWorld
|
|||
std::vector<osg::ref_ptr<const osg::Object> > mPreloadedObjects;
|
||||
};
|
||||
|
||||
class TerrainPreloadItem : public SceneUtil::WorkItem
|
||||
{
|
||||
public:
|
||||
TerrainPreloadItem(const std::vector<osg::ref_ptr<Terrain::View> >& views, Terrain::World* world, const std::vector<osg::Vec3f>& preloadPositions)
|
||||
: mAbort(false)
|
||||
, mTerrainViews(views)
|
||||
, mWorld(world)
|
||||
, mPreloadPositions(preloadPositions)
|
||||
{
|
||||
}
|
||||
|
||||
void storeViews(double referenceTime)
|
||||
{
|
||||
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size(); ++i)
|
||||
mWorld->storeView(mTerrainViews[i], referenceTime);
|
||||
}
|
||||
|
||||
virtual void doWork()
|
||||
{
|
||||
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size() && !mAbort; ++i)
|
||||
{
|
||||
mTerrainViews[i]->reset();
|
||||
mWorld->preload(mTerrainViews[i], mPreloadPositions[i], mAbort);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void abort()
|
||||
{
|
||||
mAbort = true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<bool> mAbort;
|
||||
std::vector<osg::ref_ptr<Terrain::View> > mTerrainViews;
|
||||
Terrain::World* mWorld;
|
||||
std::vector<osg::Vec3f> mPreloadPositions;
|
||||
};
|
||||
|
||||
/// Worker thread item: update the resource system's cache, effectively deleting unused entries.
|
||||
class UpdateCacheItem : public SceneUtil::WorkItem
|
||||
{
|
||||
|
@ -288,6 +326,9 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
mPreloadCells.erase(found);
|
||||
|
||||
if (cell->isExterior() && mTerrainPreloadItem && mTerrainPreloadItem->isDone())
|
||||
mTerrainPreloadItem->storeViews(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,6 +370,12 @@ namespace MWWorld
|
|||
mWorkQueue->addWorkItem(mUpdateCacheItem, true);
|
||||
mLastResourceCacheUpdate = timestamp;
|
||||
}
|
||||
|
||||
if (mTerrainPreloadItem && mTerrainPreloadItem->isDone())
|
||||
{
|
||||
mTerrainPreloadItem->storeViews(timestamp);
|
||||
mTerrainPreloadItem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CellPreloader::setExpiryDelay(double expiryDelay)
|
||||
|
@ -366,38 +413,6 @@ namespace MWWorld
|
|||
mUnrefQueue = unrefQueue;
|
||||
}
|
||||
|
||||
class TerrainPreloadItem : public SceneUtil::WorkItem
|
||||
{
|
||||
public:
|
||||
TerrainPreloadItem(const std::vector<osg::ref_ptr<Terrain::View> >& views, Terrain::World* world, const std::vector<osg::Vec3f>& preloadPositions)
|
||||
: mAbort(false)
|
||||
, mTerrainViews(views)
|
||||
, mWorld(world)
|
||||
, mPreloadPositions(preloadPositions)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void doWork()
|
||||
{
|
||||
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size() && !mAbort; ++i)
|
||||
{
|
||||
mWorld->preload(mTerrainViews[i], mPreloadPositions[i], mAbort);
|
||||
mTerrainViews[i]->reset();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void abort()
|
||||
{
|
||||
mAbort = true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<bool> mAbort;
|
||||
std::vector<osg::ref_ptr<Terrain::View> > mTerrainViews;
|
||||
Terrain::World* mWorld;
|
||||
std::vector<osg::Vec3f> mPreloadPositions;
|
||||
};
|
||||
|
||||
void CellPreloader::setTerrainPreloadPositions(const std::vector<osg::Vec3f> &positions)
|
||||
{
|
||||
if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone())
|
||||
|
@ -418,8 +433,6 @@ namespace MWWorld
|
|||
mTerrainViews.push_back(mTerrain->createView());
|
||||
}
|
||||
|
||||
// TODO: provide some way of giving the preloaded view to the main thread when we enter the cell
|
||||
// right now, we just use it to make sure the resources are preloaded
|
||||
mTerrainPreloadPositions = positions;
|
||||
mTerrainPreloadItem = new TerrainPreloadItem(mTerrainViews, mTerrain, positions);
|
||||
mWorkQueue->addWorkItem(mTerrainPreloadItem);
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace MWRender
|
|||
namespace MWWorld
|
||||
{
|
||||
class CellStore;
|
||||
class TerrainPreloadItem;
|
||||
|
||||
class CellPreloader
|
||||
{
|
||||
|
@ -105,7 +106,7 @@ namespace MWWorld
|
|||
|
||||
std::vector<osg::ref_ptr<Terrain::View> > mTerrainViews;
|
||||
std::vector<osg::Vec3f> mTerrainPreloadPositions;
|
||||
osg::ref_ptr<SceneUtil::WorkItem> mTerrainPreloadItem;
|
||||
osg::ref_ptr<TerrainPreloadItem> mTerrainPreloadItem;
|
||||
osg::ref_ptr<SceneUtil::WorkItem> mUpdateCacheItem;
|
||||
};
|
||||
|
||||
|
|
|
@ -440,8 +440,14 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
|||
if (!isCullVisitor)
|
||||
vd->reset(); // we can't reuse intersection views in the next frame because they only contain what is touched by the intersection ray.
|
||||
|
||||
vd->finishFrame(nv.getTraversalNumber());
|
||||
mRootNode->getViewDataMap()->clearUnusedViews(nv.getTraversalNumber());
|
||||
vd->markUnchanged();
|
||||
|
||||
double referenceTime = nv.getFrameStamp() ? nv.getFrameStamp()->getReferenceTime() : 0.0;
|
||||
if (referenceTime != 0.0)
|
||||
{
|
||||
vd->setLastUsageTimeStamp(referenceTime);
|
||||
mViewDataMap->clearUnusedViews(referenceTime);
|
||||
}
|
||||
}
|
||||
|
||||
void QuadTreeWorld::ensureQuadTreeBuilt()
|
||||
|
@ -504,6 +510,17 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, std::atomic
|
|||
ViewData::Entry& entry = vd->getEntry(i);
|
||||
loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get());
|
||||
}
|
||||
vd->markUnchanged();
|
||||
}
|
||||
|
||||
void 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(), needsUpdate);
|
||||
stored->copyFrom(*vd);
|
||||
stored->setLastUsageTimeStamp(referenceTime);
|
||||
}
|
||||
|
||||
void QuadTreeWorld::reportStats(unsigned int frameNumber, osg::Stats *stats)
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace Terrain
|
|||
virtual void unloadCell(int x, int y);
|
||||
|
||||
View* createView();
|
||||
|
||||
void preload(View* view, const osg::Vec3f& viewPoint, std::atomic<bool>& abort);
|
||||
void preload(View* view, const osg::Vec3f& eyePoint, std::atomic<bool>& abort);
|
||||
void storeView(const View* view, double referenceTime);
|
||||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats* stats);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Terrain
|
|||
|
||||
ViewData::ViewData()
|
||||
: mNumEntries(0)
|
||||
, mFrameLastUsed(0)
|
||||
, mLastUsageTimeStamp(0.0)
|
||||
, mChanged(false)
|
||||
, mHasViewPoint(false)
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ void ViewData::clear()
|
|||
for (unsigned int i=0; i<mEntries.size(); ++i)
|
||||
mEntries[i].set(nullptr, false);
|
||||
mNumEntries = 0;
|
||||
mFrameLastUsed = 0;
|
||||
mLastUsageTimeStamp = 0;
|
||||
mChanged = false;
|
||||
mHasViewPoint = false;
|
||||
}
|
||||
|
@ -173,12 +173,12 @@ ViewData *ViewDataMap::createOrReuseView()
|
|||
}
|
||||
}
|
||||
|
||||
void ViewDataMap::clearUnusedViews(unsigned int frame)
|
||||
void ViewDataMap::clearUnusedViews(double referenceTime)
|
||||
{
|
||||
for (Map::iterator it = mViews.begin(); it != mViews.end(); )
|
||||
{
|
||||
ViewData* vd = it->second;
|
||||
if (vd->getFrameLastUsed() + 2 < frame)
|
||||
if (vd->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
|
||||
{
|
||||
vd->clear();
|
||||
mUnusedViews.push_back(vd);
|
||||
|
|
|
@ -46,11 +46,12 @@ namespace Terrain
|
|||
|
||||
Entry& getEntry(unsigned int i);
|
||||
|
||||
unsigned int getFrameLastUsed() const { return mFrameLastUsed; }
|
||||
void finishFrame(unsigned int frame) { mFrameLastUsed = frame; mChanged = false; }
|
||||
double getLastUsageTimeStamp() const { return mLastUsageTimeStamp; }
|
||||
void setLastUsageTimeStamp(double timeStamp) { mLastUsageTimeStamp = timeStamp; }
|
||||
|
||||
/// @return Have any nodes changed since the last frame
|
||||
bool hasChanged() const;
|
||||
void markUnchanged() { mChanged = false; }
|
||||
|
||||
bool hasViewPoint() const;
|
||||
|
||||
|
@ -60,7 +61,7 @@ namespace Terrain
|
|||
private:
|
||||
std::vector<Entry> mEntries;
|
||||
unsigned int mNumEntries;
|
||||
unsigned int mFrameLastUsed;
|
||||
double mLastUsageTimeStamp;
|
||||
bool mChanged;
|
||||
osg::Vec3f mViewPoint;
|
||||
bool mHasViewPoint;
|
||||
|
@ -71,14 +72,16 @@ namespace Terrain
|
|||
{
|
||||
public:
|
||||
ViewDataMap()
|
||||
: mReuseDistance(100) // 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(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.
|
||||
// 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)
|
||||
{}
|
||||
|
||||
ViewData* getViewData(osg::Object* viewer, const osg::Vec3f& viewPoint, bool& needsUpdate);
|
||||
|
||||
ViewData* createOrReuseView();
|
||||
|
||||
void clearUnusedViews(unsigned int frame);
|
||||
void clearUnusedViews(double referenceTime);
|
||||
|
||||
void clear();
|
||||
|
||||
|
@ -93,6 +96,7 @@ namespace Terrain
|
|||
Map mViews;
|
||||
|
||||
float mReuseDistance;
|
||||
float mExpiryDelay; // time in seconds for unused view to be removed
|
||||
|
||||
std::deque<ViewData*> mUnusedViews;
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace Terrain
|
|||
/// @note Thread safe.
|
||||
virtual void clearAssociatedCaches();
|
||||
|
||||
/// Load a terrain cell at maximum LOD and store it in the View for later use.
|
||||
/// Load a terrain cell and store it in the View for later use.
|
||||
/// @note Thread safe.
|
||||
virtual void cacheCell(View* view, int x, int y) {}
|
||||
|
||||
|
@ -106,6 +106,10 @@ namespace Terrain
|
|||
|
||||
virtual void preload(View* view, const osg::Vec3f& viewPoint, std::atomic<bool>& abort) {}
|
||||
|
||||
/// 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 void reportStats(unsigned int frameNumber, osg::Stats* stats) {}
|
||||
|
||||
/// Set the default viewer (usually a Camera), used as viewpoint for any viewers that don't use their own viewpoint.
|
||||
|
|
Loading…
Reference in a new issue