mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-21 16:36:45 +00:00
Make sync terrain preloading sleep free
This reduces average time spent on in. 5 milliseconds as a base precision is quite a lot considering that for 60 FPS frame time is 1000/16 = ~16.67 ms when it's a cell loading frame and there is more important work to do rather than sleeping.
This commit is contained in:
parent
aef6ec464c
commit
605cb8db7c
9 changed files with 113 additions and 36 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include <components/terrain/world.hpp>
|
#include <components/terrain/world.hpp>
|
||||||
#include <components/sceneutil/unrefqueue.hpp>
|
#include <components/sceneutil/unrefqueue.hpp>
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/esm/loadcell.hpp>
|
||||||
|
#include <components/loadinglistener/reporter.hpp>
|
||||||
|
|
||||||
#include "../mwrender/landmanager.hpp"
|
#include "../mwrender/landmanager.hpp"
|
||||||
|
|
||||||
|
@ -157,8 +158,6 @@ namespace MWWorld
|
||||||
public:
|
public:
|
||||||
TerrainPreloadItem(const std::vector<osg::ref_ptr<Terrain::View> >& views, Terrain::World* world, const std::vector<CellPreloader::PositionCellGrid>& preloadPositions)
|
TerrainPreloadItem(const std::vector<osg::ref_ptr<Terrain::View> >& views, Terrain::World* world, const std::vector<CellPreloader::PositionCellGrid>& preloadPositions)
|
||||||
: mAbort(false)
|
: mAbort(false)
|
||||||
, mProgress(views.size())
|
|
||||||
, mProgressRange(0)
|
|
||||||
, mTerrainViews(views)
|
, mTerrainViews(views)
|
||||||
, mWorld(world)
|
, mWorld(world)
|
||||||
, mPreloadPositions(preloadPositions)
|
, mPreloadPositions(preloadPositions)
|
||||||
|
@ -178,8 +177,9 @@ namespace MWWorld
|
||||||
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size() && !mAbort; ++i)
|
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size() && !mAbort; ++i)
|
||||||
{
|
{
|
||||||
mTerrainViews[i]->reset();
|
mTerrainViews[i]->reset();
|
||||||
mWorld->preload(mTerrainViews[i], mPreloadPositions[i].first, mPreloadPositions[i].second, mAbort, mProgress[i], mProgressRange);
|
mWorld->preload(mTerrainViews[i], mPreloadPositions[i].first, mPreloadPositions[i].second, mAbort, mLoadingReporter);
|
||||||
}
|
}
|
||||||
|
mLoadingReporter.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void abort() override
|
void abort() override
|
||||||
|
@ -187,16 +187,17 @@ namespace MWWorld
|
||||||
mAbort = true;
|
mAbort = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getProgress() const { return !mProgress.empty() ? mProgress[0].load() : 0; }
|
void wait(Loading::Listener& listener) const
|
||||||
int getProgressRange() const { return !mProgress.empty() && mProgress[0].load() ? mProgressRange : 0; }
|
{
|
||||||
|
mLoadingReporter.wait(listener);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> mAbort;
|
std::atomic<bool> mAbort;
|
||||||
std::vector<std::atomic<int>> mProgress;
|
|
||||||
int mProgressRange;
|
|
||||||
std::vector<osg::ref_ptr<Terrain::View> > mTerrainViews;
|
std::vector<osg::ref_ptr<Terrain::View> > mTerrainViews;
|
||||||
Terrain::World* mWorld;
|
Terrain::World* mWorld;
|
||||||
std::vector<CellPreloader::PositionCellGrid> mPreloadPositions;
|
std::vector<CellPreloader::PositionCellGrid> mPreloadPositions;
|
||||||
|
Loading::Reporter mLoadingReporter;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Worker thread item: update the resource system's cache, effectively deleting unused entries.
|
/// Worker thread item: update the resource system's cache, effectively deleting unused entries.
|
||||||
|
@ -415,7 +416,7 @@ namespace MWWorld
|
||||||
mUnrefQueue = unrefQueue;
|
mUnrefQueue = unrefQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CellPreloader::syncTerrainLoad(const std::vector<CellPreloader::PositionCellGrid> &positions, int& progress, int& progressRange, double timestamp)
|
bool CellPreloader::syncTerrainLoad(const std::vector<CellPreloader::PositionCellGrid> &positions, double timestamp, Loading::Listener& listener)
|
||||||
{
|
{
|
||||||
if (!mTerrainPreloadItem)
|
if (!mTerrainPreloadItem)
|
||||||
return true;
|
return true;
|
||||||
|
@ -435,9 +436,8 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
progress = mTerrainPreloadItem->getProgress();
|
mTerrainPreloadItem->wait(listener);
|
||||||
progressRange = mTerrainPreloadItem->getProgressRange();
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,11 @@ namespace MWRender
|
||||||
class LandManager;
|
class LandManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
class Listener;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class CellStore;
|
class CellStore;
|
||||||
|
@ -72,7 +77,7 @@ 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 syncTerrainLoad(const std::vector<CellPreloader::PositionCellGrid> &positions, int& progress, int& progressRange, double timestamp);
|
bool syncTerrainLoad(const std::vector<CellPreloader::PositionCellGrid> &positions, double timestamp, Loading::Listener& listener);
|
||||||
void abortTerrainPreloadExcept(const PositionCellGrid *exceptPos);
|
void abortTerrainPreloadExcept(const PositionCellGrid *exceptPos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1250,23 +1250,10 @@ namespace MWWorld
|
||||||
|
|
||||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||||
Loading::ScopedLoad load(loadingListener);
|
Loading::ScopedLoad load(loadingListener);
|
||||||
int progress = 0, initialProgress = -1, progressRange = 0;
|
|
||||||
while (!mPreloader->syncTerrainLoad(vec, progress, progressRange, mRendering.getReferenceTime()))
|
loadingListener->setLabel("#{sLoadingMessage4}");
|
||||||
{
|
|
||||||
if (initialProgress == -1)
|
while (!mPreloader->syncTerrainLoad(vec, mRendering.getReferenceTime(), *loadingListener)) {}
|
||||||
{
|
|
||||||
loadingListener->setLabel("#{sLoadingMessage4}");
|
|
||||||
initialProgress = progress;
|
|
||||||
}
|
|
||||||
if (progress)
|
|
||||||
{
|
|
||||||
loadingListener->setProgressRange(std::max(0, progressRange-initialProgress));
|
|
||||||
loadingListener->setProgress(progress-initialProgress);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
loadingListener->setProgress(0);
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::reloadTerrain()
|
void Scene::reloadTerrain()
|
||||||
|
|
|
@ -197,6 +197,10 @@ add_component_dir(detournavigator
|
||||||
navmeshcacheitem
|
navmeshcacheitem
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_component_dir(loadinglistener
|
||||||
|
reporter
|
||||||
|
)
|
||||||
|
|
||||||
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
41
components/loadinglistener/reporter.cpp
Normal file
41
components/loadinglistener/reporter.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include "reporter.hpp"
|
||||||
|
#include "loadinglistener.hpp"
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
void Reporter::addTotal(std::size_t value)
|
||||||
|
{
|
||||||
|
const std::lock_guard lock(mMutex);
|
||||||
|
mTotal += value;
|
||||||
|
mUpdated.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reporter::addProgress(std::size_t value)
|
||||||
|
{
|
||||||
|
const std::lock_guard lock(mMutex);
|
||||||
|
mProgress += value;
|
||||||
|
mUpdated.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reporter::complete()
|
||||||
|
{
|
||||||
|
const std::lock_guard lock(mMutex);
|
||||||
|
mDone = true;
|
||||||
|
mUpdated.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reporter::wait(Listener& listener) const
|
||||||
|
{
|
||||||
|
std::unique_lock lock(mMutex);
|
||||||
|
while (!mDone)
|
||||||
|
{
|
||||||
|
listener.setProgressRange(mTotal);
|
||||||
|
listener.setProgress(mProgress);
|
||||||
|
mUpdated.wait(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
components/loadinglistener/reporter.hpp
Normal file
32
components/loadinglistener/reporter.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef COMPONENTS_LOADINGLISTENER_REPORTER_H
|
||||||
|
#define COMPONENTS_LOADINGLISTENER_REPORTER_H
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
class Listener;
|
||||||
|
|
||||||
|
class Reporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void addTotal(std::size_t value);
|
||||||
|
|
||||||
|
void addProgress(std::size_t value);
|
||||||
|
|
||||||
|
void complete();
|
||||||
|
|
||||||
|
void wait(Listener& listener) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t mProgress = 0;
|
||||||
|
std::size_t mTotal = 0;
|
||||||
|
bool mDone = false;
|
||||||
|
mutable std::mutex mMutex;
|
||||||
|
mutable std::condition_variable mUpdated;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -10,6 +10,7 @@
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
#include <components/sceneutil/mwshadowtechnique.hpp>
|
#include <components/sceneutil/mwshadowtechnique.hpp>
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
#include <components/loadinglistener/reporter.hpp>
|
||||||
|
|
||||||
#include "quadtreenode.hpp"
|
#include "quadtreenode.hpp"
|
||||||
#include "storage.hpp"
|
#include "storage.hpp"
|
||||||
|
@ -496,7 +497,7 @@ View* QuadTreeWorld::createView()
|
||||||
return mViewDataMap->createIndependentView();
|
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)
|
void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::Vec4i &grid, std::atomic<bool> &abort, Loading::Reporter& reporter)
|
||||||
{
|
{
|
||||||
ensureQuadTreeBuilt();
|
ensureQuadTreeBuilt();
|
||||||
|
|
||||||
|
@ -506,16 +507,18 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::
|
||||||
DefaultLodCallback lodCallback(mLodFactor, mMinSize, mViewDistance, grid);
|
DefaultLodCallback lodCallback(mLodFactor, mMinSize, mViewDistance, grid);
|
||||||
mRootNode->traverseNodes(vd, viewPoint, &lodCallback);
|
mRootNode->traverseNodes(vd, viewPoint, &lodCallback);
|
||||||
|
|
||||||
if (!progressTotal)
|
std::size_t progressTotal = 0;
|
||||||
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
|
for (unsigned int i = 0, n = vd->getNumEntries(); i < n; ++i)
|
||||||
progressTotal += vd->getEntry(i).mNode->getSize();
|
progressTotal += vd->getEntry(i).mNode->getSize();
|
||||||
|
|
||||||
|
reporter.addTotal(progressTotal);
|
||||||
|
|
||||||
const float cellWorldSize = mStorage->getCellWorldSize();
|
const float cellWorldSize = mStorage->getCellWorldSize();
|
||||||
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
|
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
|
||||||
{
|
{
|
||||||
ViewData::Entry& entry = vd->getEntry(i);
|
ViewData::Entry& entry = vd->getEntry(i);
|
||||||
loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, grid, mChunkManagers, true);
|
loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, grid, mChunkManagers, true);
|
||||||
progress += entry.mNode->getSize();
|
reporter.addProgress(entry.mNode->getSize());
|
||||||
}
|
}
|
||||||
vd->markUnchanged();
|
vd->markUnchanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace Terrain
|
||||||
void unloadCell(int x, int y) override;
|
void unloadCell(int x, int y) override;
|
||||||
|
|
||||||
View* createView() override;
|
View* createView() override;
|
||||||
void preload(View* view, const osg::Vec3f& eyePoint, const osg::Vec4i &cellgrid, std::atomic<bool>& abort, std::atomic<int>& progress, int& progressRange) override;
|
void preload(View* view, const osg::Vec3f& eyePoint, const osg::Vec4i &cellgrid, std::atomic<bool>& abort, Loading::Reporter& reporter) override;
|
||||||
bool storeView(const View* view, double referenceTime) override;
|
bool storeView(const View* view, double referenceTime) override;
|
||||||
void rebuildViews() override;
|
void rebuildViews() override;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,11 @@ namespace SceneUtil
|
||||||
class WorkQueue;
|
class WorkQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
class Reporter;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
class Storage;
|
class Storage;
|
||||||
|
@ -148,7 +153,7 @@ namespace Terrain
|
||||||
|
|
||||||
/// @note Thread safe, as long as you do not attempt to load into the same view from multiple threads.
|
/// @note Thread safe, as long as you do not attempt to load into the same view from multiple threads.
|
||||||
|
|
||||||
virtual void preload(View* view, const osg::Vec3f& viewPoint, const osg::Vec4i &cellgrid, std::atomic<bool>& abort, std::atomic<int>& progress, int& progressRange) {}
|
virtual void preload(View* view, const osg::Vec3f& viewPoint, const osg::Vec4i &cellgrid, std::atomic<bool>& abort, Loading::Reporter& reporter) {}
|
||||||
|
|
||||||
/// Store a preloaded view into the cache with the intent that the next rendering traversal can use it.
|
/// Store a preloaded view into the cache with the intent that the next rendering traversal can use it.
|
||||||
/// @note Not thread safe.
|
/// @note Not thread safe.
|
||||||
|
|
Loading…
Reference in a new issue