mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 11:26:37 +00:00 
			
		
		
		
	Merge branch 'fix_navmesh_cache_key' into 'master'
Increase navmesh cache hit rate by fixing key implementation See merge request OpenMW/openmw!584
This commit is contained in:
		
						commit
						f8c068ee34
					
				
					 9 changed files with 168 additions and 206 deletions
				
			
		|  | @ -68,7 +68,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshKeySize; |         const std::size_t navMeshKeySize = cRecastMeshKeySize; | ||||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; |         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, |         const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, | ||||||
|  | @ -81,7 +81,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshKeySize; |         const std::size_t navMeshKeySize = cRecastMeshKeySize; | ||||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); |         const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
|         const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM)); |         const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM)); | ||||||
|         NavMeshData anotherNavMeshData {anotherData, 1}; |         NavMeshData anotherNavMeshData {anotherData, 1}; | ||||||
|  | @ -97,7 +97,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshKeySize; |         const std::size_t navMeshKeySize = cRecastMeshKeySize; | ||||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; |         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData)); |         cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData)); | ||||||
|  | @ -142,7 +142,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; |         const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; | ||||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; |         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; |         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; | ||||||
|  | @ -163,7 +163,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshKeySize; |         const std::size_t navMeshKeySize = cRecastMeshKeySize; | ||||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; |         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; |         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; | ||||||
|  | @ -182,7 +182,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; |         const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; | ||||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); |         const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const std::vector<RecastMesh::Water> leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; |         const std::vector<RecastMesh::Water> leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; | ||||||
|  | @ -214,7 +214,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; |         const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; | ||||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); |         const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const std::vector<RecastMesh::Water> leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; |         const std::vector<RecastMesh::Water> leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; | ||||||
|  | @ -258,7 +258,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshKeySize; |         const std::size_t navMeshKeySize = cRecastMeshKeySize; | ||||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); |         const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; |         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; | ||||||
|  | @ -277,7 +277,7 @@ namespace | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize1 = cRecastMeshKeySize; |         const std::size_t navMeshKeySize1 = cRecastMeshKeySize; | ||||||
|         const std::size_t navMeshKeySize2 = cRecastMeshWithWaterKeySize; |         const std::size_t navMeshKeySize2 = cRecastMeshWithWaterKeySize; | ||||||
|         const std::size_t maxSize = 2 * navMeshDataSize + 2 * navMeshKeySize1 + 2 * navMeshKeySize2; |         const std::size_t maxSize = 2 * navMeshDataSize + navMeshKeySize1 + navMeshKeySize2; | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const std::vector<RecastMesh::Water> anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; |         const std::vector<RecastMesh::Water> anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; | ||||||
|  | @ -306,7 +306,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshKeySize; |         const std::size_t navMeshKeySize = cRecastMeshKeySize; | ||||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; |         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; |         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; | ||||||
|  | @ -330,7 +330,7 @@ namespace | ||||||
|     { |     { | ||||||
|         const std::size_t navMeshDataSize = 1; |         const std::size_t navMeshDataSize = 1; | ||||||
|         const std::size_t navMeshKeySize = cRecastMeshKeySize; |         const std::size_t navMeshKeySize = cRecastMeshKeySize; | ||||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; |         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||||
|         NavMeshTilesCache cache(maxSize); |         NavMeshTilesCache cache(maxSize); | ||||||
| 
 | 
 | ||||||
|         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; |         const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; | ||||||
|  |  | ||||||
|  | @ -68,4 +68,19 @@ inline std::ostream& operator <<(std::ostream& stream, BroadphaseNativeTypes val | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | inline bool operator <(const btVector3& lhs, const btVector3& rhs) | ||||||
|  | { | ||||||
|  |     return std::tie(lhs.x(), lhs.y(), lhs.z()) < std::tie(rhs.x(), rhs.y(), rhs.z()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool operator <(const btMatrix3x3& lhs, const btMatrix3x3& rhs) | ||||||
|  | { | ||||||
|  |     return std::tie(lhs[0], lhs[1], lhs[2]) < std::tie(rhs[0], rhs[1], rhs[2]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool operator <(const btTransform& lhs, const btTransform& rhs) | ||||||
|  | { | ||||||
|  |     return std::tie(lhs.getBasis(), lhs.getOrigin()) < std::tie(rhs.getBasis(), rhs.getOrigin()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -9,57 +9,29 @@ namespace DetourNavigator | ||||||
| { | { | ||||||
|     namespace |     namespace | ||||||
|     { |     { | ||||||
|         inline std::vector<unsigned char> makeNavMeshKey(const RecastMesh& recastMesh, |         inline std::size_t getSize(const RecastMesh& recastMesh, | ||||||
|             const std::vector<OffMeshConnection>& offMeshConnections) |                                    const std::vector<OffMeshConnection>& offMeshConnections) | ||||||
|         { |         { | ||||||
|             const std::size_t indicesSize = recastMesh.getIndices().size() * sizeof(int); |             const std::size_t indicesSize = recastMesh.getIndices().size() * sizeof(int); | ||||||
|             const std::size_t verticesSize = recastMesh.getVertices().size() * sizeof(float); |             const std::size_t verticesSize = recastMesh.getVertices().size() * sizeof(float); | ||||||
|             const std::size_t areaTypesSize = recastMesh.getAreaTypes().size() * sizeof(AreaType); |             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 waterSize = recastMesh.getWater().size() * sizeof(RecastMesh::Water); | ||||||
|             const std::size_t offMeshConnectionsSize = offMeshConnections.size() * sizeof(OffMeshConnection); |             const std::size_t offMeshConnectionsSize = offMeshConnections.size() * sizeof(OffMeshConnection); | ||||||
| 
 |             return indicesSize + verticesSize + areaTypesSize + waterSize + offMeshConnectionsSize; | ||||||
|             std::vector<unsigned char> result(indicesSize + verticesSize + areaTypesSize + waterSize + offMeshConnectionsSize); |  | ||||||
|             unsigned char* dst = result.data(); |  | ||||||
| 
 |  | ||||||
|             if (indicesSize > 0) |  | ||||||
|             { |  | ||||||
|                 std::memcpy(dst, recastMesh.getIndices().data(), indicesSize); |  | ||||||
|                 dst += indicesSize; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (verticesSize > 0) |  | ||||||
|             { |  | ||||||
|                 std::memcpy(dst, recastMesh.getVertices().data(), verticesSize); |  | ||||||
|                 dst += verticesSize; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (areaTypesSize > 0) |  | ||||||
|             { |  | ||||||
|                 std::memcpy(dst, recastMesh.getAreaTypes().data(), areaTypesSize); |  | ||||||
|                 dst += areaTypesSize; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (waterSize > 0) |  | ||||||
|             { |  | ||||||
|                 std::memcpy(dst, recastMesh.getWater().data(), waterSize); |  | ||||||
|                 dst += waterSize; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (offMeshConnectionsSize > 0) |  | ||||||
|                 std::memcpy(dst, offMeshConnections.data(), offMeshConnectionsSize); |  | ||||||
| 
 |  | ||||||
|             return result; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     NavMeshTilesCache::NavMeshTilesCache(const std::size_t maxNavMeshDataSize) |     NavMeshTilesCache::NavMeshTilesCache(const std::size_t maxNavMeshDataSize) | ||||||
|         : mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0) {} |         : mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0), | ||||||
|  |           mHitCount(0), mGetCount(0) {} | ||||||
| 
 | 
 | ||||||
|     NavMeshTilesCache::Value NavMeshTilesCache::get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, |     NavMeshTilesCache::Value NavMeshTilesCache::get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, | ||||||
|         const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections) |         const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections) | ||||||
|     { |     { | ||||||
|         const std::lock_guard<std::mutex> lock(mMutex); |         const std::lock_guard<std::mutex> lock(mMutex); | ||||||
| 
 | 
 | ||||||
|  |         ++mGetCount; | ||||||
|  | 
 | ||||||
|         const auto agentValues = mValues.find(agentHalfExtents); |         const auto agentValues = mValues.find(agentHalfExtents); | ||||||
|         if (agentValues == mValues.end()) |         if (agentValues == mValues.end()) | ||||||
|             return Value(); |             return Value(); | ||||||
|  | @ -68,12 +40,14 @@ namespace DetourNavigator | ||||||
|         if (tileValues == agentValues->second.end()) |         if (tileValues == agentValues->second.end()) | ||||||
|             return Value(); |             return Value(); | ||||||
| 
 | 
 | ||||||
|         const auto tile = tileValues->second.mMap.find(RecastMeshKeyView(recastMesh, offMeshConnections)); |         const auto tile = tileValues->second.mMap.find(NavMeshKeyView(recastMesh, offMeshConnections)); | ||||||
|         if (tile == tileValues->second.mMap.end()) |         if (tile == tileValues->second.mMap.end()) | ||||||
|             return Value(); |             return Value(); | ||||||
| 
 | 
 | ||||||
|         acquireItemUnsafe(tile->second); |         acquireItemUnsafe(tile->second); | ||||||
| 
 | 
 | ||||||
|  |         ++mHitCount; | ||||||
|  | 
 | ||||||
|         return Value(*this, tile->second); |         return Value(*this, tile->second); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -81,26 +55,22 @@ namespace DetourNavigator | ||||||
|         const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections, |         const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections, | ||||||
|         NavMeshData&& value) |         NavMeshData&& value) | ||||||
|     { |     { | ||||||
|         const auto navMeshSize = static_cast<std::size_t>(value.mSize); |         const auto itemSize = static_cast<std::size_t>(value.mSize) + getSize(recastMesh, offMeshConnections); | ||||||
| 
 | 
 | ||||||
|         const std::lock_guard<std::mutex> lock(mMutex); |         const std::lock_guard<std::mutex> lock(mMutex); | ||||||
| 
 | 
 | ||||||
|         if (navMeshSize > mMaxNavMeshDataSize) |  | ||||||
|             return Value(); |  | ||||||
| 
 |  | ||||||
|         if (navMeshSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) |  | ||||||
|             return Value(); |  | ||||||
| 
 |  | ||||||
|         auto navMeshKey = makeNavMeshKey(recastMesh, offMeshConnections); |  | ||||||
|         const auto itemSize = navMeshSize + 2 * navMeshKey.size(); |  | ||||||
| 
 |  | ||||||
|         if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) |         if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize)) | ||||||
|             return Value(); |             return Value(); | ||||||
| 
 | 
 | ||||||
|         while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize) |         while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize) | ||||||
|             removeLeastRecentlyUsed(); |             removeLeastRecentlyUsed(); | ||||||
| 
 | 
 | ||||||
|         const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(navMeshKey)); |         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[agentHalfExtents][changedTile].mMap.emplace(iterator->mNavMeshKey, iterator); |         const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(iterator->mNavMeshKey, iterator); | ||||||
| 
 | 
 | ||||||
|         if (!emplaced.second) |         if (!emplaced.second) | ||||||
|  | @ -123,17 +93,22 @@ namespace DetourNavigator | ||||||
|         std::size_t navMeshCacheSize = 0; |         std::size_t navMeshCacheSize = 0; | ||||||
|         std::size_t usedNavMeshTiles = 0; |         std::size_t usedNavMeshTiles = 0; | ||||||
|         std::size_t cachedNavMeshTiles = 0; |         std::size_t cachedNavMeshTiles = 0; | ||||||
|  |         std::size_t hitCount = 0; | ||||||
|  |         std::size_t getCount = 0; | ||||||
| 
 | 
 | ||||||
|         { |         { | ||||||
|             const std::lock_guard<std::mutex> lock(mMutex); |             const std::lock_guard<std::mutex> lock(mMutex); | ||||||
|             navMeshCacheSize = mUsedNavMeshDataSize; |             navMeshCacheSize = mUsedNavMeshDataSize; | ||||||
|             usedNavMeshTiles = mBusyItems.size(); |             usedNavMeshTiles = mBusyItems.size(); | ||||||
|             cachedNavMeshTiles = mFreeItems.size(); |             cachedNavMeshTiles = mFreeItems.size(); | ||||||
|  |             hitCount = mHitCount; | ||||||
|  |             getCount = mGetCount; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         stats.setAttribute(frameNumber, "NavMesh CacheSize", navMeshCacheSize); |         stats.setAttribute(frameNumber, "NavMesh CacheSize", navMeshCacheSize); | ||||||
|         stats.setAttribute(frameNumber, "NavMesh UsedTiles", usedNavMeshTiles); |         stats.setAttribute(frameNumber, "NavMesh UsedTiles", usedNavMeshTiles); | ||||||
|         stats.setAttribute(frameNumber, "NavMesh CachedTiles", cachedNavMeshTiles); |         stats.setAttribute(frameNumber, "NavMesh CachedTiles", cachedNavMeshTiles); | ||||||
|  |         stats.setAttribute(frameNumber, "NavMesh CacheHitRate", static_cast<double>(hitCount) / getCount * 100.0); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void NavMeshTilesCache::removeLeastRecentlyUsed() |     void NavMeshTilesCache::removeLeastRecentlyUsed() | ||||||
|  | @ -152,8 +127,8 @@ namespace DetourNavigator | ||||||
|         if (value == tileValues->second.mMap.end()) |         if (value == tileValues->second.mMap.end()) | ||||||
|             return; |             return; | ||||||
| 
 | 
 | ||||||
|         mUsedNavMeshDataSize -= getSize(item); |         mUsedNavMeshDataSize -= item.mSize; | ||||||
|         mFreeNavMeshDataSize -= getSize(item); |         mFreeNavMeshDataSize -= item.mSize; | ||||||
| 
 | 
 | ||||||
|         tileValues->second.mMap.erase(value); |         tileValues->second.mMap.erase(value); | ||||||
|         mFreeItems.pop_back(); |         mFreeItems.pop_back(); | ||||||
|  | @ -174,7 +149,7 @@ namespace DetourNavigator | ||||||
|             return; |             return; | ||||||
| 
 | 
 | ||||||
|         mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator); |         mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator); | ||||||
|         mFreeNavMeshDataSize -= getSize(*iterator); |         mFreeNavMeshDataSize -= iterator->mSize; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void NavMeshTilesCache::releaseItem(ItemIterator iterator) |     void NavMeshTilesCache::releaseItem(ItemIterator iterator) | ||||||
|  | @ -185,71 +160,6 @@ namespace DetourNavigator | ||||||
|         const std::lock_guard<std::mutex> lock(mMutex); |         const std::lock_guard<std::mutex> lock(mMutex); | ||||||
| 
 | 
 | ||||||
|         mFreeItems.splice(mFreeItems.begin(), mBusyItems, iterator); |         mFreeItems.splice(mFreeItems.begin(), mBusyItems, iterator); | ||||||
|         mFreeNavMeshDataSize += getSize(*iterator); |         mFreeNavMeshDataSize += iterator->mSize; | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     namespace |  | ||||||
|     { |  | ||||||
|         struct CompareBytes |  | ||||||
|         { |  | ||||||
|             const unsigned char* mRhsIt; |  | ||||||
|             const unsigned char* const mRhsEnd; |  | ||||||
| 
 |  | ||||||
|             template <class T> |  | ||||||
|             int operator ()(const std::vector<T>& lhs) |  | ||||||
|             { |  | ||||||
|                 const auto lhsBegin = reinterpret_cast<const char*>(lhs.data()); |  | ||||||
|                 const auto lhsEnd = reinterpret_cast<const char*>(lhs.data() + lhs.size()); |  | ||||||
|                 const auto lhsSize = static_cast<std::ptrdiff_t>(lhsEnd - lhsBegin); |  | ||||||
|                 const auto rhsSize = static_cast<std::ptrdiff_t>(mRhsEnd - mRhsIt); |  | ||||||
| 
 |  | ||||||
|                 if (lhsBegin == nullptr || mRhsIt == nullptr) |  | ||||||
|                 { |  | ||||||
|                     if (lhsSize < rhsSize) |  | ||||||
|                         return -1; |  | ||||||
|                     else if (lhsSize > rhsSize) |  | ||||||
|                         return 1; |  | ||||||
|                     else |  | ||||||
|                         return 0; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 const auto size = std::min(lhsSize, rhsSize); |  | ||||||
| 
 |  | ||||||
|                 if (const auto result = std::memcmp(lhsBegin, mRhsIt, size)) |  | ||||||
|                     return result; |  | ||||||
| 
 |  | ||||||
|                 if (lhsSize > rhsSize) |  | ||||||
|                     return 1; |  | ||||||
| 
 |  | ||||||
|                 mRhsIt += size; |  | ||||||
| 
 |  | ||||||
|                 return 0; |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     int NavMeshTilesCache::RecastMeshKeyView::compare(const std::vector<unsigned char>& other) const |  | ||||||
|     { |  | ||||||
|         CompareBytes compareBytes {other.data(), other.data() + other.size()}; |  | ||||||
| 
 |  | ||||||
|         if (const auto result = compareBytes(mRecastMesh.get().getIndices())) |  | ||||||
|             return result; |  | ||||||
| 
 |  | ||||||
|         if (const auto result = compareBytes(mRecastMesh.get().getVertices())) |  | ||||||
|             return result; |  | ||||||
| 
 |  | ||||||
|         if (const auto result = compareBytes(mRecastMesh.get().getAreaTypes())) |  | ||||||
|             return result; |  | ||||||
| 
 |  | ||||||
|         if (const auto result = compareBytes(mRecastMesh.get().getWater())) |  | ||||||
|             return result; |  | ||||||
| 
 |  | ||||||
|         if (const auto result = compareBytes(mOffMeshConnections.get())) |  | ||||||
|             return result; |  | ||||||
| 
 |  | ||||||
|         if (compareBytes.mRhsIt < compareBytes.mRhsEnd) |  | ||||||
|             return -1; |  | ||||||
| 
 |  | ||||||
|         return 0; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -27,6 +27,89 @@ namespace DetourNavigator | ||||||
|         int mSize; |         int mSize; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     struct RecastMeshData | ||||||
|  |     { | ||||||
|  |         std::vector<int> mIndices; | ||||||
|  |         std::vector<float> mVertices; | ||||||
|  |         std::vector<AreaType> mAreaTypes; | ||||||
|  |         std::vector<RecastMesh::Water> mWater; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const RecastMeshData& lhs, const RecastMeshData& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes, lhs.mWater) | ||||||
|  |                 < std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes, rhs.mWater); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const RecastMeshData& lhs, const RecastMesh& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes, lhs.mWater) | ||||||
|  |                 < std::tie(rhs.getIndices(), rhs.getVertices(), rhs.getAreaTypes(), rhs.getWater()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const RecastMesh& lhs, const RecastMeshData& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.getIndices(), lhs.getVertices(), lhs.getAreaTypes(), lhs.getWater()) | ||||||
|  |                 < std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes, rhs.mWater); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     struct NavMeshKey | ||||||
|  |     { | ||||||
|  |         RecastMeshData mRecastMesh; | ||||||
|  |         std::vector<OffMeshConnection> mOffMeshConnections; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const NavMeshKey& lhs, const NavMeshKey& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.mRecastMesh, lhs.mOffMeshConnections) | ||||||
|  |                 < std::tie(rhs.mRecastMesh, rhs.mOffMeshConnections); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     struct NavMeshKeyRef | ||||||
|  |     { | ||||||
|  |         std::reference_wrapper<const NavMeshKey> mRef; | ||||||
|  | 
 | ||||||
|  |         explicit NavMeshKeyRef(const NavMeshKey& ref) : mRef(ref) {} | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const NavMeshKeyRef& lhs, const NavMeshKeyRef& rhs) | ||||||
|  |     { | ||||||
|  |         return lhs.mRef.get() < rhs.mRef.get(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     struct NavMeshKeyView | ||||||
|  |     { | ||||||
|  |         std::reference_wrapper<const RecastMesh> mRecastMesh; | ||||||
|  |         std::reference_wrapper<const std::vector<OffMeshConnection>> mOffMeshConnections; | ||||||
|  | 
 | ||||||
|  |         NavMeshKeyView(const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections) | ||||||
|  |             : mRecastMesh(recastMesh), mOffMeshConnections(offMeshConnections) {} | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const NavMeshKeyView& lhs, const NavMeshKey& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.mRecastMesh.get(), lhs.mOffMeshConnections.get()) | ||||||
|  |                 < std::tie(rhs.mRecastMesh, rhs.mOffMeshConnections); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const NavMeshKey& lhs, const NavMeshKeyView& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.mRecastMesh, lhs.mOffMeshConnections) | ||||||
|  |                 < std::tie(rhs.mRecastMesh.get(), rhs.mOffMeshConnections.get()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     template <class R> | ||||||
|  |     inline bool operator <(const NavMeshKeyRef& lhs, const R& rhs) | ||||||
|  |     { | ||||||
|  |         return lhs.mRef.get() < rhs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     template <class L> | ||||||
|  |     inline bool operator <(const L& lhs, const NavMeshKeyRef& rhs) | ||||||
|  |     { | ||||||
|  |         return lhs < rhs.mRef.get(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     class NavMeshTilesCache |     class NavMeshTilesCache | ||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|  | @ -35,14 +118,16 @@ namespace DetourNavigator | ||||||
|             std::atomic<std::int64_t> mUseCount; |             std::atomic<std::int64_t> mUseCount; | ||||||
|             osg::Vec3f mAgentHalfExtents; |             osg::Vec3f mAgentHalfExtents; | ||||||
|             TilePosition mChangedTile; |             TilePosition mChangedTile; | ||||||
|             std::vector<unsigned char> mNavMeshKey; |             NavMeshKey mNavMeshKey; | ||||||
|             NavMeshData mNavMeshData; |             NavMeshData mNavMeshData; | ||||||
|  |             std::size_t mSize; | ||||||
| 
 | 
 | ||||||
|             Item(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, std::vector<unsigned char>&& navMeshKey) |             Item(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, NavMeshKey&& navMeshKey, std::size_t size) | ||||||
|                 : mUseCount(0) |                 : mUseCount(0) | ||||||
|                 , mAgentHalfExtents(agentHalfExtents) |                 , mAgentHalfExtents(agentHalfExtents) | ||||||
|                 , mChangedTile(changedTile) |                 , mChangedTile(changedTile) | ||||||
|                 , mNavMeshKey(std::move(navMeshKey)) |                 , mNavMeshKey(navMeshKey) | ||||||
|  |                 , mSize(size) | ||||||
|             {} |             {} | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|  | @ -115,85 +200,17 @@ namespace DetourNavigator | ||||||
|         void reportStats(unsigned int frameNumber, osg::Stats& stats) const; |         void reportStats(unsigned int frameNumber, osg::Stats& stats) const; | ||||||
| 
 | 
 | ||||||
|     private: |     private: | ||||||
|         class KeyView |  | ||||||
|         { |  | ||||||
|         public: |  | ||||||
|             KeyView() = default; |  | ||||||
| 
 |  | ||||||
|             virtual ~KeyView() = default; |  | ||||||
| 
 |  | ||||||
|             KeyView(const std::vector<unsigned char>& value) |  | ||||||
|                 : mValue(&value) {} |  | ||||||
| 
 |  | ||||||
|             const std::vector<unsigned char>& getValue() const |  | ||||||
|             { |  | ||||||
|                 assert(mValue); |  | ||||||
|                 return *mValue; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             virtual int compare(const std::vector<unsigned char>& other) const |  | ||||||
|             { |  | ||||||
|                 assert(mValue); |  | ||||||
| 
 |  | ||||||
|                 const auto valueSize = mValue->size(); |  | ||||||
|                 const auto otherSize = other.size(); |  | ||||||
| 
 |  | ||||||
|                 if (const auto result = std::memcmp(mValue->data(), other.data(), std::min(valueSize, otherSize))) |  | ||||||
|                     return result; |  | ||||||
| 
 |  | ||||||
|                 if (valueSize < otherSize) |  | ||||||
|                     return -1; |  | ||||||
| 
 |  | ||||||
|                 if (valueSize > otherSize) |  | ||||||
|                     return 1; |  | ||||||
| 
 |  | ||||||
|                 return 0; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             virtual bool isLess(const KeyView& other) const |  | ||||||
|             { |  | ||||||
|                 assert(mValue); |  | ||||||
|                 return other.compare(*mValue) > 0; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             friend bool operator <(const KeyView& lhs, const KeyView& rhs) |  | ||||||
|             { |  | ||||||
|                 return lhs.isLess(rhs); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         private: |  | ||||||
|             const std::vector<unsigned char>* mValue = nullptr; |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         class RecastMeshKeyView : public KeyView |  | ||||||
|         { |  | ||||||
|         public: |  | ||||||
|             RecastMeshKeyView(const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections) |  | ||||||
|                 : mRecastMesh(recastMesh), mOffMeshConnections(offMeshConnections) {} |  | ||||||
| 
 |  | ||||||
|             int compare(const std::vector<unsigned char>& other) const override; |  | ||||||
| 
 |  | ||||||
|             bool isLess(const KeyView& other) const override |  | ||||||
|             { |  | ||||||
|                 return compare(other.getValue()) < 0; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             virtual ~RecastMeshKeyView() = default; |  | ||||||
| 
 |  | ||||||
|         private: |  | ||||||
|             std::reference_wrapper<const RecastMesh> mRecastMesh; |  | ||||||
|             std::reference_wrapper<const std::vector<OffMeshConnection>> mOffMeshConnections; |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         struct TileMap |         struct TileMap | ||||||
|         { |         { | ||||||
|             std::map<KeyView, ItemIterator> mMap; |             std::map<NavMeshKeyRef, ItemIterator, std::less<>> mMap; | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         mutable std::mutex mMutex; |         mutable std::mutex mMutex; | ||||||
|         std::size_t mMaxNavMeshDataSize; |         std::size_t mMaxNavMeshDataSize; | ||||||
|         std::size_t mUsedNavMeshDataSize; |         std::size_t mUsedNavMeshDataSize; | ||||||
|         std::size_t mFreeNavMeshDataSize; |         std::size_t mFreeNavMeshDataSize; | ||||||
|  |         std::size_t mHitCount; | ||||||
|  |         std::size_t mGetCount; | ||||||
|         std::list<Item> mBusyItems; |         std::list<Item> mBusyItems; | ||||||
|         std::list<Item> mFreeItems; |         std::list<Item> mFreeItems; | ||||||
|         std::map<osg::Vec3f, std::map<TilePosition, TileMap>> mValues; |         std::map<osg::Vec3f, std::map<TilePosition, TileMap>> mValues; | ||||||
|  | @ -203,11 +220,6 @@ namespace DetourNavigator | ||||||
|         void acquireItemUnsafe(ItemIterator iterator); |         void acquireItemUnsafe(ItemIterator iterator); | ||||||
| 
 | 
 | ||||||
|         void releaseItem(ItemIterator iterator); |         void releaseItem(ItemIterator iterator); | ||||||
| 
 |  | ||||||
|         static std::size_t getSize(const Item& item) |  | ||||||
|         { |  | ||||||
|             return static_cast<std::size_t>(item.mNavMeshData.mSize) + 2 * item.mNavMeshKey.size(); |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ | ||||||
| 
 | 
 | ||||||
| #include <osg/Vec3f> | #include <osg/Vec3f> | ||||||
| 
 | 
 | ||||||
|  | #include <tuple> | ||||||
|  | 
 | ||||||
| namespace DetourNavigator | namespace DetourNavigator | ||||||
| { | { | ||||||
|     struct OffMeshConnection |     struct OffMeshConnection | ||||||
|  | @ -13,6 +15,11 @@ namespace DetourNavigator | ||||||
|         osg::Vec3f mEnd; |         osg::Vec3f mEnd; | ||||||
|         AreaType mAreaType; |         AreaType mAreaType; | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     inline bool operator<(const OffMeshConnection& lhs, const OffMeshConnection& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.mStart, lhs.mEnd, lhs.mAreaType) < std::tie(rhs.mStart, rhs.mEnd, rhs.mAreaType); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -85,6 +85,8 @@ namespace DetourNavigator | ||||||
|                     std::for_each(byId.first, byId.second, [&] (const auto& v) { result.push_back(v.second); }); |                     std::for_each(byId.first, byId.second, [&] (const auto& v) { result.push_back(v.second); }); | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|  |             std::sort(result.begin(), result.end()); | ||||||
|  | 
 | ||||||
|             return result; |             return result; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,9 +5,12 @@ | ||||||
| #include "chunkytrimesh.hpp" | #include "chunkytrimesh.hpp" | ||||||
| #include "bounds.hpp" | #include "bounds.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include <components/bullethelpers/operators.hpp> | ||||||
|  | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <tuple> | ||||||
| 
 | 
 | ||||||
| #include <osg/Vec3f> | #include <osg/Vec3f> | ||||||
| 
 | 
 | ||||||
|  | @ -87,6 +90,17 @@ namespace DetourNavigator | ||||||
|         ChunkyTriMesh mChunkyTriMesh; |         ChunkyTriMesh mChunkyTriMesh; | ||||||
|         Bounds mBounds; |         Bounds mBounds; | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     inline bool operator<(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.mCellSize, lhs.mTransform) < std::tie(rhs.mCellSize, rhs.mTransform); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const RecastMesh& lhs, const RecastMesh& rhs) | ||||||
|  |     { | ||||||
|  |         return std::tie(lhs.getIndices(), lhs.getVertices(), lhs.getAreaTypes(), lhs.getWater()) | ||||||
|  |                 < std::tie(rhs.getIndices(), rhs.getVertices(), rhs.getAreaTypes(), rhs.getWater()); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -155,6 +155,7 @@ namespace DetourNavigator | ||||||
|     std::shared_ptr<RecastMesh> RecastMeshBuilder::create(std::size_t generation, std::size_t revision) |     std::shared_ptr<RecastMesh> RecastMeshBuilder::create(std::size_t generation, std::size_t revision) | ||||||
|     { |     { | ||||||
|         optimizeRecastMesh(mIndices, mVertices); |         optimizeRecastMesh(mIndices, mVertices); | ||||||
|  |         std::sort(mWater.begin(), mWater.end()); | ||||||
|         return std::make_shared<RecastMesh>(generation, revision, mIndices, mVertices, mAreaTypes, |         return std::make_shared<RecastMesh>(generation, revision, mIndices, mVertices, mAreaTypes, | ||||||
|             mWater, mSettings.get().mTrianglesPerChunk); |             mWater, mSettings.get().mTrianglesPerChunk); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -394,6 +394,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) | ||||||
|             "NavMesh CacheSize", |             "NavMesh CacheSize", | ||||||
|             "NavMesh UsedTiles", |             "NavMesh UsedTiles", | ||||||
|             "NavMesh CachedTiles", |             "NavMesh CachedTiles", | ||||||
|  |             "NavMesh CacheHitRate", | ||||||
|             "", |             "", | ||||||
|             "Mechanics Actors", |             "Mechanics Actors", | ||||||
|             "Mechanics Objects", |             "Mechanics Objects", | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue