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/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()))
{
if (initialProgress == -1)
{
loadingListener->setLabel("#{sLoadingMessage4}"); loadingListener->setLabel("#{sLoadingMessage4}");
initialProgress = progress;
} while (!mPreloader->syncTerrainLoad(vec, mRendering.getReferenceTime(), *loadingListener)) {}
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
) )

@ -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/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…
Cancel
Save