You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/detournavigator/navmeshtilescache.cpp

122 lines
3.9 KiB
C++

#include "navmeshtilescache.hpp"
#include "stats.hpp"
#include <cstring>
namespace DetourNavigator
{
NavMeshTilesCache::NavMeshTilesCache(const std::size_t maxNavMeshDataSize)
: mMaxNavMeshDataSize(maxNavMeshDataSize)
, mUsedNavMeshDataSize(0)
, mFreeNavMeshDataSize(0)
, mHitCount(0)
, mGetCount(0)
{
}
NavMeshTilesCache::Value NavMeshTilesCache::get(
const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh)
{
const std::lock_guard<std::mutex> lock(mMutex);
++mGetCount;
const auto tile = mValues.find(std::tie(agentBounds, changedTile, recastMesh));
if (tile == mValues.end())
return Value();
acquireItemUnsafe(tile->second);
++mHitCount;
return Value(*this, tile->second);
}
NavMeshTilesCache::Value NavMeshTilesCache::set(const AgentBounds& agentBounds, const TilePosition& changedTile,
const RecastMesh& recastMesh, std::unique_ptr<PreparedNavMeshData>&& value)
{
const auto itemSize = sizeof(RecastMesh) + getSize(recastMesh)
+ (value == nullptr ? 0 : sizeof(PreparedNavMeshData) + getSize(*value));
const std::lock_guard<std::mutex> lock(mMutex);
if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize))
return Value();
while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize)
removeLeastRecentlyUsed();
RecastMeshData key{ recastMesh.getMesh(), recastMesh.getWater(), recastMesh.getHeightfields(),
recastMesh.getFlatHeightfields() };
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentBounds, changedTile, std::move(key), itemSize);
const auto emplaced = mValues.emplace(
std::make_tuple(agentBounds, changedTile, std::cref(iterator->mRecastMeshData)), iterator);
if (!emplaced.second)
{
mFreeItems.erase(iterator);
acquireItemUnsafe(emplaced.first->second);
++mGetCount;
++mHitCount;
return Value(*this, emplaced.first->second);
}
iterator->mPreparedNavMeshData = std::move(value);
++iterator->mUseCount;
mUsedNavMeshDataSize += itemSize;
mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator);
return Value(*this, iterator);
}
NavMeshTilesCacheStats NavMeshTilesCache::getStats() const
{
NavMeshTilesCacheStats result;
{
const std::lock_guard<std::mutex> lock(mMutex);
result.mNavMeshCacheSize = mUsedNavMeshDataSize;
result.mUsedNavMeshTiles = mBusyItems.size();
result.mCachedNavMeshTiles = mFreeItems.size();
result.mHitCount = mHitCount;
result.mGetCount = mGetCount;
}
return result;
}
void NavMeshTilesCache::removeLeastRecentlyUsed()
{
const auto& item = mFreeItems.back();
const auto value = mValues.find(std::tie(item.mAgentBounds, item.mChangedTile, item.mRecastMeshData));
if (value == mValues.end())
return;
mUsedNavMeshDataSize -= item.mSize;
mFreeNavMeshDataSize -= item.mSize;
mValues.erase(value);
mFreeItems.pop_back();
}
void NavMeshTilesCache::acquireItemUnsafe(ItemIterator iterator)
{
if (++iterator->mUseCount > 1)
return;
mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator);
mFreeNavMeshDataSize -= iterator->mSize;
}
void NavMeshTilesCache::releaseItem(ItemIterator iterator)
{
if (--iterator->mUseCount > 0)
return;
const std::lock_guard<std::mutex> lock(mMutex);
mFreeItems.splice(mFreeItems.begin(), mBusyItems, iterator);
mFreeNavMeshDataSize += iterator->mSize;
}
}