mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-27 18:41:05 +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
@ -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
|
||||
)
|
||||
|
||||
|
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/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…
x
Reference in New Issue
Block a user