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-tes3mp/components/detournavigator/navmeshtilescache.cpp

142 lines
5.3 KiB
C++

#include "navmeshtilescache.hpp"
#include <osg/Stats>
#include <cstring>
namespace DetourNavigator
{
namespace
{
inline std::size_t getSize(const RecastMesh& recastMesh,
const std::vector<OffMeshConnection>& offMeshConnections)
{
const std::size_t indicesSize = recastMesh.getIndices().size() * sizeof(int);
const std::size_t verticesSize = recastMesh.getVertices().size() * sizeof(float);
const std::size_t areaTypesSize = recastMesh.getAreaTypes().size() * sizeof(AreaType);
const std::size_t waterSize = recastMesh.getWater().size() * sizeof(RecastMesh::Water);
const std::size_t offMeshConnectionsSize = offMeshConnections.size() * sizeof(OffMeshConnection);
return indicesSize + verticesSize + areaTypesSize + waterSize + offMeshConnectionsSize;
}
}
NavMeshTilesCache::NavMeshTilesCache(const std::size_t maxNavMeshDataSize)
: mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0),
mHitCount(0), mGetCount(0) {}
NavMeshTilesCache::Value NavMeshTilesCache::get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile,
const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections)
{
const std::lock_guard<std::mutex> lock(mMutex);
++mGetCount;
const auto tile = mValues.find(std::make_tuple(agentHalfExtents, changedTile, NavMeshKeyView(recastMesh, offMeshConnections)));
if (tile == mValues.end())
return Value();
acquireItemUnsafe(tile->second);
++mHitCount;
return Value(*this, tile->second);
}
NavMeshTilesCache::Value NavMeshTilesCache::set(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile,
const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections,
NavMeshData&& value)
{
const auto itemSize = static_cast<std::size_t>(value.mSize) + getSize(recastMesh, offMeshConnections);
const std::lock_guard<std::mutex> lock(mMutex);
if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize))
return Value();
while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize)
removeLeastRecentlyUsed();
NavMeshKey navMeshKey {
RecastMeshData {recastMesh.getIndices(), recastMesh.getVertices(), recastMesh.getAreaTypes(), recastMesh.getWater()},
offMeshConnections
};
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(navMeshKey), itemSize);
const auto emplaced = mValues.emplace(std::make_tuple(agentHalfExtents, changedTile, NavMeshKeyRef(iterator->mNavMeshKey)), iterator);
if (!emplaced.second)
{
mFreeItems.erase(iterator);
acquireItemUnsafe(emplaced.first->second);
++mGetCount;
++mHitCount;
return Value(*this, emplaced.first->second);
}
iterator->mNavMeshData = std::move(value);
++iterator->mUseCount;
mUsedNavMeshDataSize += itemSize;
mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator);
return Value(*this, iterator);
}
NavMeshTilesCache::Stats NavMeshTilesCache::getStats() const
{
Stats 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::reportStats(unsigned int frameNumber, osg::Stats& out) const
{
const Stats stats = getStats();
out.setAttribute(frameNumber, "NavMesh CacheSize", stats.mNavMeshCacheSize);
out.setAttribute(frameNumber, "NavMesh UsedTiles", stats.mUsedNavMeshTiles);
out.setAttribute(frameNumber, "NavMesh CachedTiles", stats.mCachedNavMeshTiles);
out.setAttribute(frameNumber, "NavMesh CacheHitRate", static_cast<double>(stats.mHitCount) / stats.mGetCount * 100.0);
}
void NavMeshTilesCache::removeLeastRecentlyUsed()
{
const auto& item = mFreeItems.back();
const auto value = mValues.find(std::make_tuple(item.mAgentHalfExtents, item.mChangedTile, NavMeshKeyRef(item.mNavMeshKey)));
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;
}
}