Merge branch 'cleanup_preloading' into 'master'

Cleanup preloading code

See merge request OpenMW/openmw!4104
esm4-texture
Alexei Kotov 7 months ago
commit 03652104fe

@ -84,6 +84,7 @@ add_openmw_dir (mwworld
store esmstore fallback actionrepair actionsoulgem livecellref actiondoor store esmstore fallback actionrepair actionsoulgem livecellref actiondoor
contentloader esmloader actiontrap cellreflist cellref weather projectilemanager contentloader esmloader actiontrap cellreflist cellref weather projectilemanager
cellpreloader datetimemanager groundcoverstore magiceffects cell ptrregistry cellpreloader datetimemanager groundcoverstore magiceffects cell ptrregistry
positioncellgrid
) )
add_openmw_dir (mwphysics add_openmw_dir (mwphysics

@ -1,8 +1,9 @@
#include "cellpreloader.hpp" #include "cellpreloader.hpp"
#include <array> #include <algorithm>
#include <atomic> #include <atomic>
#include <limits> #include <limits>
#include <span>
#include <osg/Stats> #include <osg/Stats>
@ -26,32 +27,27 @@
#include "cellstore.hpp" #include "cellstore.hpp"
#include "class.hpp" #include "class.hpp"
namespace namespace MWWorld
{ {
template <class Contained> namespace
bool contains(const std::vector<MWWorld::CellPreloader::PositionCellGrid>& container, const Contained& contained,
float tolerance)
{ {
for (const auto& pos : contained) bool contains(std::span<const PositionCellGrid> positions, const PositionCellGrid& contained, float tolerance)
{ {
bool found = false; const float squaredTolerance = tolerance * tolerance;
for (const auto& pos2 : container) const auto predicate = [&](const PositionCellGrid& v) {
{ return (contained.mPosition - v.mPosition).length2() < squaredTolerance
if ((pos.first - pos2.first).length2() < tolerance * tolerance && pos.second == pos2.second) && contained.mCellBounds == v.mCellBounds;
{ };
found = true; return std::ranges::any_of(positions, predicate);
break;
}
}
if (!found)
return false;
} }
return true;
}
}
namespace MWWorld bool contains(
{ std::span<const PositionCellGrid> container, std::span<const PositionCellGrid> contained, float tolerance)
{
const auto predicate = [&](const PositionCellGrid& v) { return contains(container, v, tolerance); };
return std::ranges::all_of(contained, predicate);
}
}
struct ListModelsVisitor struct ListModelsVisitor
{ {
@ -169,12 +165,12 @@ namespace MWWorld
class TerrainPreloadItem : public SceneUtil::WorkItem class TerrainPreloadItem : public SceneUtil::WorkItem
{ {
public: public:
TerrainPreloadItem(const std::vector<osg::ref_ptr<Terrain::View>>& views, Terrain::World* world, explicit TerrainPreloadItem(const std::vector<osg::ref_ptr<Terrain::View>>& views, Terrain::World* world,
const std::vector<CellPreloader::PositionCellGrid>& preloadPositions) std::span<const PositionCellGrid> preloadPositions)
: mAbort(false) : mAbort(false)
, mTerrainViews(views) , mTerrainViews(views)
, mWorld(world) , mWorld(world)
, mPreloadPositions(preloadPositions) , mPreloadPositions(preloadPositions.begin(), preloadPositions.end())
{ {
} }
@ -183,8 +179,8 @@ 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, mWorld->preload(mTerrainViews[i], mPreloadPositions[i].mPosition, mPreloadPositions[i].mCellBounds,
mLoadingReporter); mAbort, mLoadingReporter);
} }
mLoadingReporter.complete(); mLoadingReporter.complete();
} }
@ -197,7 +193,7 @@ namespace MWWorld
std::atomic<bool> mAbort; std::atomic<bool> mAbort;
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<PositionCellGrid> mPreloadPositions;
Loading::Reporter mLoadingReporter; Loading::Reporter mLoadingReporter;
}; };
@ -375,19 +371,19 @@ namespace MWWorld
mTerrainPreloadItem->wait(listener); mTerrainPreloadItem->wait(listener);
} }
void CellPreloader::abortTerrainPreloadExcept(const CellPreloader::PositionCellGrid* exceptPos) void CellPreloader::abortTerrainPreloadExcept(const PositionCellGrid* exceptPos)
{ {
if (exceptPos && contains(mTerrainPreloadPositions, std::array{ *exceptPos }, Constants::CellSizeInUnits)) if (exceptPos != nullptr && contains(mTerrainPreloadPositions, *exceptPos, Constants::CellSizeInUnits))
return; return;
if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone()) if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone())
{ {
mTerrainPreloadItem->abort(); mTerrainPreloadItem->abort();
mTerrainPreloadItem->waitTillDone(); mTerrainPreloadItem->waitTillDone();
} }
setTerrainPreloadPositions(std::vector<CellPreloader::PositionCellGrid>()); setTerrainPreloadPositions({});
} }
void CellPreloader::setTerrainPreloadPositions(const std::vector<CellPreloader::PositionCellGrid>& positions) void CellPreloader::setTerrainPreloadPositions(std::span<const PositionCellGrid> positions)
{ {
if (positions.empty()) if (positions.empty())
{ {
@ -408,7 +404,7 @@ namespace MWWorld
mTerrainViews.emplace_back(mTerrain->createView()); mTerrainViews.emplace_back(mTerrain->createView());
} }
mTerrainPreloadPositions = positions; mTerrainPreloadPositions.assign(positions.begin(), positions.end());
if (!positions.empty()) if (!positions.empty())
{ {
mTerrainPreloadItem = new TerrainPreloadItem(mTerrainViews, mTerrain, positions); mTerrainPreloadItem = new TerrainPreloadItem(mTerrainViews, mTerrain, positions);
@ -417,10 +413,10 @@ namespace MWWorld
} }
} }
bool CellPreloader::isTerrainLoaded(const CellPreloader::PositionCellGrid& position, double referenceTime) const bool CellPreloader::isTerrainLoaded(const PositionCellGrid& position, double referenceTime) const
{ {
return mLoadedTerrainTimestamp + mResourceSystem->getSceneManager()->getExpiryDelay() > referenceTime return mLoadedTerrainTimestamp + mResourceSystem->getSceneManager()->getExpiryDelay() > referenceTime
&& contains(mLoadedTerrainPositions, std::array{ position }, Constants::CellSizeInUnits); && contains(mLoadedTerrainPositions, position, Constants::CellSizeInUnits);
} }
void CellPreloader::setTerrain(Terrain::World* terrain) void CellPreloader::setTerrain(Terrain::World* terrain)

@ -1,15 +1,14 @@
#ifndef OPENMW_MWWORLD_CELLPRELOADER_H #ifndef OPENMW_MWWORLD_CELLPRELOADER_H
#define OPENMW_MWWORLD_CELLPRELOADER_H #define OPENMW_MWWORLD_CELLPRELOADER_H
#include <components/sceneutil/workqueue.hpp> #include "positioncellgrid.hpp"
#include <map> #include <components/sceneutil/workqueue.hpp>
#include <osg/Vec3f>
#include <osg/Vec4i>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <map> #include <map>
#include <span>
namespace osg namespace osg
{ {
@ -79,12 +78,11 @@ namespace MWWorld
void setWorkQueue(osg::ref_ptr<SceneUtil::WorkQueue> workQueue); void setWorkQueue(osg::ref_ptr<SceneUtil::WorkQueue> workQueue);
typedef std::pair<osg::Vec3f, osg::Vec4i> PositionCellGrid; void setTerrainPreloadPositions(std::span<const PositionCellGrid> positions);
void setTerrainPreloadPositions(const std::vector<PositionCellGrid>& positions);
void syncTerrainLoad(Loading::Listener& listener); void syncTerrainLoad(Loading::Listener& listener);
void abortTerrainPreloadExcept(const PositionCellGrid* exceptPos); void abortTerrainPreloadExcept(const PositionCellGrid* exceptPos);
bool isTerrainLoaded(const CellPreloader::PositionCellGrid& position, double referenceTime) const; bool isTerrainLoaded(const PositionCellGrid& position, double referenceTime) const;
void setTerrain(Terrain::World* terrain); void setTerrain(Terrain::World* terrain);
void reportStats(unsigned int frameNumber, osg::Stats& stats) const; void reportStats(unsigned int frameNumber, osg::Stats& stats) const;

@ -0,0 +1,16 @@
#ifndef OPENMW_APPS_OPENMW_MWWORLD_POSITIONCELLGRID_H
#define OPENMW_APPS_OPENMW_MWWORLD_POSITIONCELLGRID_H
#include <osg/Vec3f>
#include <osg/Vec4i>
namespace MWWorld
{
struct PositionCellGrid
{
osg::Vec3f mPosition;
osg::Vec4i mCellBounds;
};
}
#endif

@ -603,7 +603,7 @@ namespace MWWorld
mPreloader->setTerrain(mRendering.getTerrain()); mPreloader->setTerrain(mRendering.getTerrain());
if (mRendering.pagingUnlockCache()) if (mRendering.pagingUnlockCache())
mPreloader->abortTerrainPreloadExcept(nullptr); mPreloader->abortTerrainPreloadExcept(nullptr);
if (!mPreloader->isTerrainLoaded(std::make_pair(pos, newGrid), mRendering.getReferenceTime())) if (!mPreloader->isTerrainLoaded(PositionCellGrid{ pos, newGrid }, mRendering.getReferenceTime()))
preloadTerrain(pos, playerCellIndex.mWorldspace, true); preloadTerrain(pos, playerCellIndex.mWorldspace, true);
mPagedRefs.clear(); mPagedRefs.clear();
mRendering.getPagedRefnums(newGrid, mPagedRefs); mRendering.getPagedRefnums(newGrid, mPagedRefs);
@ -1093,26 +1093,25 @@ namespace MWWorld
osg::Vec3f predictedPos = playerPos + moved / dt * mPredictionTime; osg::Vec3f predictedPos = playerPos + moved / dt * mPredictionTime;
if (mCurrentCell->isExterior()) if (mCurrentCell->isExterior())
exteriorPositions.emplace_back( exteriorPositions.push_back(PositionCellGrid{
predictedPos, gridCenterToBounds(getNewGridCenter(predictedPos, &mCurrentGridCenter))); predictedPos, gridCenterToBounds(getNewGridCenter(predictedPos, &mCurrentGridCenter)) });
mLastPlayerPos = playerPos; mLastPlayerPos = playerPos;
if (mPreloadEnabled) if (mPreloadEnabled)
{ {
if (mPreloadDoors) if (mPreloadDoors)
preloadTeleportDoorDestinations(playerPos, predictedPos, exteriorPositions); preloadTeleportDoorDestinations(playerPos, predictedPos);
if (mPreloadExteriorGrid) if (mPreloadExteriorGrid)
preloadExteriorGrid(playerPos, predictedPos); preloadExteriorGrid(playerPos, predictedPos);
if (mPreloadFastTravel) if (mPreloadFastTravel)
preloadFastTravelDestinations(playerPos, predictedPos, exteriorPositions); preloadFastTravelDestinations(playerPos, exteriorPositions);
} }
mPreloader->setTerrainPreloadPositions(exteriorPositions); mPreloader->setTerrainPreloadPositions(exteriorPositions);
} }
void Scene::preloadTeleportDoorDestinations( void Scene::preloadTeleportDoorDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos)
const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos, std::vector<PositionCellGrid>& exteriorPositions)
{ {
std::vector<MWWorld::ConstPtr> teleportDoors; std::vector<MWWorld::ConstPtr> teleportDoors;
for (const MWWorld::CellStore* cellStore : mActiveCells) for (const MWWorld::CellStore* cellStore : mActiveCells)
@ -1232,10 +1231,9 @@ namespace MWWorld
void Scene::preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync) void Scene::preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync)
{ {
ESM::ExteriorCellLocation cellPos = ESM::positionToExteriorCellLocation(pos.x(), pos.y(), worldspace); ESM::ExteriorCellLocation cellPos = ESM::positionToExteriorCellLocation(pos.x(), pos.y(), worldspace);
std::vector<PositionCellGrid> vec; const PositionCellGrid position{ pos, gridCenterToBounds({ cellPos.mX, cellPos.mY }) };
vec.emplace_back(pos, gridCenterToBounds({ cellPos.mX, cellPos.mY })); mPreloader->abortTerrainPreloadExcept(&position);
mPreloader->abortTerrainPreloadExcept(vec.data()); mPreloader->setTerrainPreloadPositions(std::span(&position, 1));
mPreloader->setTerrainPreloadPositions(vec);
if (!sync) if (!sync)
return; return;
@ -1249,7 +1247,7 @@ namespace MWWorld
void Scene::reloadTerrain() void Scene::reloadTerrain()
{ {
mPreloader->setTerrainPreloadPositions(std::vector<PositionCellGrid>()); mPreloader->setTerrainPreloadPositions({});
} }
struct ListFastTravelDestinationsVisitor struct ListFastTravelDestinationsVisitor
@ -1282,12 +1280,10 @@ namespace MWWorld
std::vector<ESM::Transport::Dest> mList; std::vector<ESM::Transport::Dest> mList;
}; };
void Scene::preloadFastTravelDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& /*predictedPos*/, void Scene::preloadFastTravelDestinations(
std::vector<PositionCellGrid>& exteriorPositions) // ignore predictedPos here since opening dialogue with const osg::Vec3f& playerPos, std::vector<PositionCellGrid>& exteriorPositions)
// travel service takes extra time
{ {
const MWWorld::ConstPtr player = mWorld.getPlayerPtr(); ListFastTravelDestinationsVisitor listVisitor(mPreloadDistance, playerPos);
ListFastTravelDestinationsVisitor listVisitor(mPreloadDistance, player.getRefData().getPosition().asVec3());
ESM::RefId extWorldspace = mWorld.getCurrentWorldspace(); ESM::RefId extWorldspace = mWorld.getCurrentWorldspace();
for (MWWorld::CellStore* cellStore : mActiveCells) for (MWWorld::CellStore* cellStore : mActiveCells)
{ {
@ -1305,7 +1301,7 @@ namespace MWWorld
const ESM::ExteriorCellLocation cellIndex const ESM::ExteriorCellLocation cellIndex
= ESM::positionToExteriorCellLocation(pos.x(), pos.y(), extWorldspace); = ESM::positionToExteriorCellLocation(pos.x(), pos.y(), extWorldspace);
preloadCellWithSurroundings(mWorld.getWorldModel().getExterior(cellIndex)); preloadCellWithSurroundings(mWorld.getWorldModel().getExterior(cellIndex));
exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); exteriorPositions.push_back(PositionCellGrid{ pos, gridCenterToBounds(getNewGridCenter(pos)) });
} }
} }
} }

@ -5,6 +5,7 @@
#include <osg/Vec4i> #include <osg/Vec4i>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include "positioncellgrid.hpp"
#include "ptr.hpp" #include "ptr.hpp"
#include <memory> #include <memory>
@ -122,14 +123,11 @@ namespace MWWorld
void requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent = true); void requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent = true);
typedef std::pair<osg::Vec3f, osg::Vec4i> PositionCellGrid;
void preloadCells(float dt); void preloadCells(float dt);
void preloadTeleportDoorDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos, void preloadTeleportDoorDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos);
std::vector<PositionCellGrid>& exteriorPositions);
void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos); void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos);
void preloadFastTravelDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos, void preloadFastTravelDestinations(
std::vector<PositionCellGrid>& exteriorPositions); const osg::Vec3f& playerPos, std::vector<PositionCellGrid>& exteriorPositions);
osg::Vec4i gridCenterToBounds(const osg::Vec2i& centerCell) const; osg::Vec4i gridCenterToBounds(const osg::Vec2i& centerCell) const;
osg::Vec2i getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter = nullptr) const; osg::Vec2i getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter = nullptr) const;

@ -70,7 +70,6 @@ namespace Terrain
mNodes.clear(); mNodes.clear();
} }
} }
const osg::Vec4i& getActiveGrid() const { return mActiveGrid; }
unsigned int getWorldUpdateRevision() const { return mWorldUpdateRevision; } unsigned int getWorldUpdateRevision() const { return mWorldUpdateRevision; }
void setWorldUpdateRevision(int updateRevision) { mWorldUpdateRevision = updateRevision; } void setWorldUpdateRevision(int updateRevision) { mWorldUpdateRevision = updateRevision; }

Loading…
Cancel
Save