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.
pull/3096/head
elsid 3 years ago
parent aef6ec464c
commit 605cb8db7c
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -14,6 +14,7 @@
#include <components/terrain/world.hpp>
#include <components/sceneutil/unrefqueue.hpp>
#include <components/esm/loadcell.hpp>
#include <components/loadinglistener/reporter.hpp>
#include "../mwrender/landmanager.hpp"
@ -157,8 +158,6 @@ namespace MWWorld
public:
TerrainPreloadItem(const std::vector<osg::ref_ptr<Terrain::View> >& views, Terrain::World* world, const std::vector<CellPreloader::PositionCellGrid>& preloadPositions)
: mAbort(false)
, mProgress(views.size())
, mProgressRange(0)
, mTerrainViews(views)
, mWorld(world)
, mPreloadPositions(preloadPositions)
@ -178,8 +177,9 @@ namespace MWWorld
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size() && !mAbort; ++i)
{
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
@ -187,16 +187,17 @@ namespace MWWorld
mAbort = true;
}
int getProgress() const { return !mProgress.empty() ? mProgress[0].load() : 0; }
int getProgressRange() const { return !mProgress.empty() && mProgress[0].load() ? mProgressRange : 0; }
void wait(Loading::Listener& listener) const
{
mLoadingReporter.wait(listener);
}
private:
std::atomic<bool> mAbort;
std::vector<std::atomic<int>> mProgress;
int mProgressRange;
std::vector<osg::ref_ptr<Terrain::View> > mTerrainViews;
Terrain::World* mWorld;
std::vector<CellPreloader::PositionCellGrid> mPreloadPositions;
Loading::Reporter mLoadingReporter;
};
/// Worker thread item: update the resource system's cache, effectively deleting unused entries.
@ -415,7 +416,7 @@ namespace MWWorld
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)
return true;
@ -435,9 +436,8 @@ namespace MWWorld
}
else
{
progress = mTerrainPreloadItem->getProgress();
progressRange = mTerrainPreloadItem->getProgressRange();
return false;
mTerrainPreloadItem->wait(listener);
return true;
}
}

@ -29,6 +29,11 @@ namespace MWRender
class LandManager;
}
namespace Loading
{
class Listener;
}
namespace MWWorld
{
class CellStore;
@ -72,7 +77,7 @@ namespace MWWorld
typedef std::pair<osg::Vec3f, osg::Vec4i> PositionCellGrid;
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);
private:

@ -1250,23 +1250,10 @@ namespace MWWorld
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);
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
loadingListener->setLabel("#{sLoadingMessage4}");
while (!mPreloader->syncTerrainLoad(vec, mRendering.getReferenceTime(), *loadingListener)) {}
}
void Scene::reloadTerrain()

@ -197,6 +197,10 @@ add_component_dir(detournavigator
navmeshcacheitem
)
add_component_dir(loadinglistener
reporter
)
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
)

@ -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);
}
}
}

@ -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/sceneutil/mwshadowtechnique.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/loadinglistener/reporter.hpp>
#include "quadtreenode.hpp"
#include "storage.hpp"
@ -496,7 +497,7 @@ View* QuadTreeWorld::createView()
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();
@ -506,16 +507,18 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::
DefaultLodCallback lodCallback(mLodFactor, mMinSize, mViewDistance, grid);
mRootNode->traverseNodes(vd, viewPoint, &lodCallback);
if (!progressTotal)
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
progressTotal += vd->getEntry(i).mNode->getSize();
std::size_t progressTotal = 0;
for (unsigned int i = 0, n = vd->getNumEntries(); i < n; ++i)
progressTotal += vd->getEntry(i).mNode->getSize();
reporter.addTotal(progressTotal);
const float cellWorldSize = mStorage->getCellWorldSize();
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
{
ViewData::Entry& entry = vd->getEntry(i);
loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, grid, mChunkManagers, true);
progress += entry.mNode->getSize();
reporter.addProgress(entry.mNode->getSize());
}
vd->markUnchanged();
}

@ -39,7 +39,7 @@ namespace Terrain
void unloadCell(int x, int y) 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;
void rebuildViews() override;

@ -32,6 +32,11 @@ namespace SceneUtil
class WorkQueue;
}
namespace Loading
{
class Reporter;
}
namespace Terrain
{
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.
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.
/// @note Not thread safe.

Loading…
Cancel
Save