mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-28 15:11:36 +00:00
Merge branch 'fix_cell_preloading' into 'master'
Fix exterior cell preloading (#7954) Closes #7954 See merge request OpenMW/openmw!4064
This commit is contained in:
commit
fa5c8f4a13
5 changed files with 83 additions and 74 deletions
|
@ -225,8 +225,6 @@ namespace MWWorld
|
|||
, mTerrain(terrain)
|
||||
, mLandManager(landManager)
|
||||
, mExpiryDelay(0.0)
|
||||
, mMinCacheSize(0)
|
||||
, mMaxCacheSize(0)
|
||||
, mPreloadInstances(true)
|
||||
, mLastResourceCacheUpdate(0.0)
|
||||
, mLoadedTerrainTimestamp(0.0)
|
||||
|
@ -361,26 +359,11 @@ namespace MWWorld
|
|||
mExpiryDelay = expiryDelay;
|
||||
}
|
||||
|
||||
void CellPreloader::setMinCacheSize(unsigned int num)
|
||||
{
|
||||
mMinCacheSize = num;
|
||||
}
|
||||
|
||||
void CellPreloader::setMaxCacheSize(unsigned int num)
|
||||
{
|
||||
mMaxCacheSize = num;
|
||||
}
|
||||
|
||||
void CellPreloader::setPreloadInstances(bool preload)
|
||||
{
|
||||
mPreloadInstances = preload;
|
||||
}
|
||||
|
||||
unsigned int CellPreloader::getMaxCacheSize() const
|
||||
{
|
||||
return mMaxCacheSize;
|
||||
}
|
||||
|
||||
void CellPreloader::setWorkQueue(osg::ref_ptr<SceneUtil::WorkQueue> workQueue)
|
||||
{
|
||||
mWorkQueue = workQueue;
|
||||
|
|
|
@ -65,15 +65,17 @@ namespace MWWorld
|
|||
void setExpiryDelay(double expiryDelay);
|
||||
|
||||
/// The minimum number of preloaded cells before unused cells get thrown out.
|
||||
void setMinCacheSize(unsigned int num);
|
||||
void setMinCacheSize(std::size_t value) { mMinCacheSize = value; }
|
||||
|
||||
/// The maximum number of preloaded cells.
|
||||
void setMaxCacheSize(unsigned int num);
|
||||
void setMaxCacheSize(std::size_t value) { mMaxCacheSize = value; }
|
||||
|
||||
/// Enables the creation of instances in the preloading thread.
|
||||
void setPreloadInstances(bool preload);
|
||||
|
||||
unsigned int getMaxCacheSize() const;
|
||||
std::size_t getMaxCacheSize() const { return mMaxCacheSize; }
|
||||
|
||||
std::size_t getCacheSize() const { return mPreloadCells.size(); }
|
||||
|
||||
void setWorkQueue(osg::ref_ptr<SceneUtil::WorkQueue> workQueue);
|
||||
|
||||
|
@ -96,8 +98,8 @@ namespace MWWorld
|
|||
MWRender::LandManager* mLandManager;
|
||||
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
|
||||
double mExpiryDelay;
|
||||
unsigned int mMinCacheSize;
|
||||
unsigned int mMaxCacheSize;
|
||||
std::size_t mMinCacheSize = 0;
|
||||
std::size_t mMaxCacheSize = 0;
|
||||
bool mPreloadInstances;
|
||||
|
||||
double mLastResourceCacheUpdate;
|
||||
|
|
|
@ -270,6 +270,29 @@ namespace
|
|||
pagedRefs.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Function>
|
||||
void iterateOverCellsAround(int cellX, int cellY, int range, Function&& f)
|
||||
{
|
||||
for (int x = cellX - range, lastX = cellX + range; x <= lastX; ++x)
|
||||
for (int y = cellY - range, lastY = cellY + range; y <= lastY; ++y)
|
||||
f(x, y);
|
||||
}
|
||||
|
||||
void sortCellsToLoad(int centerX, int centerY, std::vector<std::pair<int, int>>& cells)
|
||||
{
|
||||
const auto getDistanceToPlayerCell = [&](const std::pair<int, int>& cellPosition) {
|
||||
return std::abs(cellPosition.first - centerX) + std::abs(cellPosition.second - centerY);
|
||||
};
|
||||
|
||||
const auto getCellPositionPriority = [&](const std::pair<int, int>& cellPosition) {
|
||||
return std::make_pair(getDistanceToPlayerCell(cellPosition), getCellPositionDistanceToOrigin(cellPosition));
|
||||
};
|
||||
|
||||
std::sort(cells.begin(), cells.end(), [&](const std::pair<int, int>& lhs, const std::pair<int, int>& rhs) {
|
||||
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -585,44 +608,24 @@ namespace MWWorld
|
|||
mPagedRefs.clear();
|
||||
mRendering.getPagedRefnums(newGrid, mPagedRefs);
|
||||
|
||||
std::size_t refsToLoad = 0;
|
||||
const auto cellsToLoad = [&](CellStoreCollection& collection, int range) -> std::vector<std::pair<int, int>> {
|
||||
std::vector<std::pair<int, int>> cellsPositionsToLoad;
|
||||
for (int x = playerCellX - range; x <= playerCellX + range; ++x)
|
||||
{
|
||||
for (int y = playerCellY - range; y <= playerCellY + range; ++y)
|
||||
{
|
||||
if (!isCellInCollection(ESM::ExteriorCellLocation(x, y, playerCellIndex.mWorldspace), collection))
|
||||
{
|
||||
refsToLoad += mWorld.getWorldModel().getExterior(playerCellIndex).count();
|
||||
cellsPositionsToLoad.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cellsPositionsToLoad;
|
||||
};
|
||||
|
||||
addPostponedPhysicsObjects();
|
||||
|
||||
auto cellsPositionsToLoad = cellsToLoad(mActiveCells, mHalfGridSize);
|
||||
std::size_t refsToLoad = 0;
|
||||
std::vector<std::pair<int, int>> cellsPositionsToLoad;
|
||||
iterateOverCellsAround(playerCellX, playerCellY, mHalfGridSize, [&](int x, int y) {
|
||||
const ESM::ExteriorCellLocation location(x, y, playerCellIndex.mWorldspace);
|
||||
if (isCellInCollection(location, mActiveCells))
|
||||
return;
|
||||
refsToLoad += mWorld.getWorldModel().getExterior(location).count();
|
||||
cellsPositionsToLoad.emplace_back(x, y);
|
||||
});
|
||||
|
||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||
Loading::ScopedLoad load(loadingListener);
|
||||
loadingListener->setLabel("#{OMWEngine:LoadingExterior}");
|
||||
loadingListener->setProgressRange(refsToLoad);
|
||||
|
||||
const auto getDistanceToPlayerCell = [&](const std::pair<int, int>& cellPosition) {
|
||||
return std::abs(cellPosition.first - playerCellX) + std::abs(cellPosition.second - playerCellY);
|
||||
};
|
||||
|
||||
const auto getCellPositionPriority = [&](const std::pair<int, int>& cellPosition) {
|
||||
return std::make_pair(getDistanceToPlayerCell(cellPosition), getCellPositionDistanceToOrigin(cellPosition));
|
||||
};
|
||||
|
||||
std::sort(cellsPositionsToLoad.begin(), cellsPositionsToLoad.end(),
|
||||
[&](const std::pair<int, int>& lhs, const std::pair<int, int>& rhs) {
|
||||
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
||||
});
|
||||
sortCellsToLoad(playerCellX, playerCellY, cellsPositionsToLoad);
|
||||
|
||||
for (const auto& [x, y] : cellsPositionsToLoad)
|
||||
{
|
||||
|
@ -1136,7 +1139,7 @@ namespace MWWorld
|
|||
{
|
||||
try
|
||||
{
|
||||
preloadCell(mWorld.getWorldModel().getCell(door.getCellRef().getDestCell()));
|
||||
preloadCellWithSurroundings(mWorld.getWorldModel().getCell(door.getCellRef().getDestCell()));
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
|
@ -1183,27 +1186,47 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
void Scene::preloadCell(CellStore& cell, bool preloadSurrounding)
|
||||
void Scene::preloadCellWithSurroundings(CellStore& cell)
|
||||
{
|
||||
if (preloadSurrounding && cell.isExterior())
|
||||
if (!cell.isExterior())
|
||||
{
|
||||
int x = cell.getCell()->getGridX();
|
||||
int y = cell.getCell()->getGridY();
|
||||
unsigned int numpreloaded = 0;
|
||||
for (int dx = -mHalfGridSize; dx <= mHalfGridSize; ++dx)
|
||||
{
|
||||
for (int dy = -mHalfGridSize; dy <= mHalfGridSize; ++dy)
|
||||
{
|
||||
mPreloader->preload(mWorld.getWorldModel().getExterior(
|
||||
ESM::ExteriorCellLocation(x + dx, y + dy, cell.getCell()->getWorldSpace())),
|
||||
mRendering.getReferenceTime());
|
||||
if (++numpreloaded >= mPreloader->getMaxCacheSize())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
mPreloader->preload(cell, mRendering.getReferenceTime());
|
||||
return;
|
||||
}
|
||||
|
||||
const int cellX = cell.getCell()->getGridX();
|
||||
const int cellY = cell.getCell()->getGridY();
|
||||
|
||||
std::vector<std::pair<int, int>> cells;
|
||||
const std::size_t gridSize = static_cast<std::size_t>(2 * mHalfGridSize + 1);
|
||||
cells.reserve(gridSize * gridSize);
|
||||
|
||||
iterateOverCellsAround(cellX, cellY, mHalfGridSize, [&](int x, int y) { cells.emplace_back(x, y); });
|
||||
|
||||
sortCellsToLoad(cellX, cellY, cells);
|
||||
|
||||
const std::size_t leftCapacity = mPreloader->getMaxCacheSize() - mPreloader->getCacheSize();
|
||||
if (cells.size() > leftCapacity)
|
||||
{
|
||||
static bool logged = [&] {
|
||||
Log(Debug::Warning) << "Not enough cell preloader cache capacity to preload exterior cells, consider "
|
||||
"increasing \"preload cell cache max\" up to "
|
||||
<< (mPreloader->getCacheSize() + cells.size());
|
||||
return true;
|
||||
}();
|
||||
(void)logged;
|
||||
cells.resize(leftCapacity);
|
||||
}
|
||||
|
||||
const ESM::RefId worldspace = cell.getCell()->getWorldSpace();
|
||||
for (const auto& [x, y] : cells)
|
||||
mPreloader->preload(mWorld.getWorldModel().getExterior(ESM::ExteriorCellLocation(x, y, worldspace)),
|
||||
mRendering.getReferenceTime());
|
||||
}
|
||||
|
||||
void Scene::preloadCell(CellStore& cell)
|
||||
{
|
||||
mPreloader->preload(cell, mRendering.getReferenceTime());
|
||||
}
|
||||
|
||||
void Scene::preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync)
|
||||
|
@ -1281,7 +1304,7 @@ namespace MWWorld
|
|||
osg::Vec3f pos = dest.mPos.asVec3();
|
||||
const ESM::ExteriorCellLocation cellIndex
|
||||
= ESM::positionToExteriorCellLocation(pos.x(), pos.y(), extWorldspace);
|
||||
preloadCell(mWorld.getWorldModel().getExterior(cellIndex), true);
|
||||
preloadCellWithSurroundings(mWorld.getWorldModel().getExterior(cellIndex));
|
||||
exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,8 @@ namespace MWWorld
|
|||
|
||||
~Scene();
|
||||
|
||||
void preloadCell(MWWorld::CellStore& cell, bool preloadSurrounding = false);
|
||||
void preloadCellWithSurroundings(MWWorld::CellStore& cell);
|
||||
void preloadCell(MWWorld::CellStore& cell);
|
||||
void preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync = false);
|
||||
void reloadTerrain();
|
||||
|
||||
|
|
|
@ -523,7 +523,7 @@ namespace MWWorld
|
|||
if (getPlayerPtr().getCell()->isExterior())
|
||||
mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3(),
|
||||
getPlayerPtr().getCell()->getCell()->getWorldSpace());
|
||||
mWorldScene->preloadCell(*getPlayerPtr().getCell(), true);
|
||||
mWorldScene->preloadCellWithSurroundings(*getPlayerPtr().getCell());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue