mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-03 17:37:18 +00:00
beeb882ea8
To reduce cache size and make it more flexible. Adding off mesh connections to the navmesh is the last step of navmesh generation and it's very fast comparing to other steps (microseconds vs milliseconds). Having less cache size makes get and set operations almost 2x times faster that also have an order of microseconds. So in total there is no performance impact.
125 lines
4.3 KiB
C++
125 lines
4.3 KiB
C++
#include "navmeshtilescache.hpp"
|
|
|
|
#include <osg/Stats>
|
|
|
|
#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 osg::Vec3f& agentHalfExtents, const TilePosition& changedTile,
|
|
const RecastMesh& recastMesh)
|
|
{
|
|
const std::lock_guard<std::mutex> lock(mMutex);
|
|
|
|
++mGetCount;
|
|
|
|
const auto tile = mValues.find(std::make_tuple(agentHalfExtents, changedTile, recastMesh));
|
|
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, 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.getIndices(), recastMesh.getVertices(), recastMesh.getAreaTypes(), recastMesh.getWater()};
|
|
|
|
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(key), itemSize);
|
|
const auto emplaced = mValues.emplace(std::make_tuple(agentHalfExtents, 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);
|
|
}
|
|
|
|
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, std::cref(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;
|
|
}
|
|
}
|