1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-07-01 22:41:34 +00:00

Merge branch 'cleanup_preloading' into 'master'

Cleanup preloading code

See merge request OpenMW/openmw!4104
This commit is contained in:
Alexei Kotov 2024-05-19 20:39:28 +00:00
commit 03652104fe
7 changed files with 74 additions and 70 deletions

View file

@ -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

View file

@ -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
{
template <class Contained>
bool contains(const std::vector<MWWorld::CellPreloader::PositionCellGrid>& container, const Contained& contained,
float tolerance)
{
for (const auto& pos : contained)
{
bool found = false;
for (const auto& pos2 : container)
{
if ((pos.first - pos2.first).length2() < tolerance * tolerance && pos.second == pos2.second)
{
found = true;
break;
}
}
if (!found)
return false;
}
return true;
}
}
namespace MWWorld namespace MWWorld
{ {
namespace
{
bool contains(std::span<const PositionCellGrid> positions, const PositionCellGrid& contained, float tolerance)
{
const float squaredTolerance = tolerance * tolerance;
const auto predicate = [&](const PositionCellGrid& v) {
return (contained.mPosition - v.mPosition).length2() < squaredTolerance
&& contained.mCellBounds == v.mCellBounds;
};
return std::ranges::any_of(positions, predicate);
}
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)

View file

@ -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 "positioncellgrid.hpp"
#include <components/sceneutil/workqueue.hpp> #include <components/sceneutil/workqueue.hpp>
#include <map>
#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;

View file

@ -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

View file

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

View file

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

View file

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