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 navMeshKeySize = cRecastMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, | ||||
|  | @ -81,7 +81,7 @@ namespace | |||
|     { | ||||
|         const std::size_t navMeshDataSize = 1; | ||||
|         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); | ||||
|         const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM)); | ||||
|         NavMeshData anotherNavMeshData {anotherData, 1}; | ||||
|  | @ -97,7 +97,7 @@ namespace | |||
|     { | ||||
|         const std::size_t navMeshDataSize = 1; | ||||
|         const std::size_t navMeshKeySize = cRecastMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData)); | ||||
|  | @ -142,7 +142,7 @@ namespace | |||
|     { | ||||
|         const std::size_t navMeshDataSize = 1; | ||||
|         const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         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 navMeshKeySize = cRecastMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         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 navMeshKeySize = cRecastMeshWithWaterKeySize; | ||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); | ||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         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 navMeshKeySize = cRecastMeshWithWaterKeySize; | ||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); | ||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         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 navMeshKeySize = cRecastMeshKeySize; | ||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); | ||||
|         const std::size_t maxSize = 2 * (navMeshDataSize + navMeshKeySize); | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         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 navMeshKeySize1 = cRecastMeshKeySize; | ||||
|         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); | ||||
| 
 | ||||
|         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 navMeshKeySize = cRecastMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         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 navMeshKeySize = cRecastMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; | ||||
|         const std::size_t maxSize = navMeshDataSize + navMeshKeySize; | ||||
|         NavMeshTilesCache cache(maxSize); | ||||
| 
 | ||||
|         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 | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ namespace DetourNavigator | |||
| { | ||||
|     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::size_t indicesSize = recastMesh.getIndices().size() * sizeof(int); | ||||
|  | @ -17,49 +17,21 @@ namespace DetourNavigator | |||
|             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); | ||||
| 
 | ||||
|             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; | ||||
|             return indicesSize + verticesSize + areaTypesSize + waterSize + offMeshConnectionsSize; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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, | ||||
|         const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections) | ||||
|     { | ||||
|         const std::lock_guard<std::mutex> lock(mMutex); | ||||
| 
 | ||||
|         ++mGetCount; | ||||
| 
 | ||||
|         const auto agentValues = mValues.find(agentHalfExtents); | ||||
|         if (agentValues == mValues.end()) | ||||
|             return Value(); | ||||
|  | @ -68,12 +40,14 @@ namespace DetourNavigator | |||
|         if (tileValues == agentValues->second.end()) | ||||
|             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()) | ||||
|             return Value(); | ||||
| 
 | ||||
|         acquireItemUnsafe(tile->second); | ||||
| 
 | ||||
|         ++mHitCount; | ||||
| 
 | ||||
|         return Value(*this, tile->second); | ||||
|     } | ||||
| 
 | ||||
|  | @ -81,26 +55,22 @@ namespace DetourNavigator | |||
|         const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections, | ||||
|         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); | ||||
| 
 | ||||
|         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)) | ||||
|             return Value(); | ||||
| 
 | ||||
|         while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize) | ||||
|             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); | ||||
| 
 | ||||
|         if (!emplaced.second) | ||||
|  | @ -123,17 +93,22 @@ namespace DetourNavigator | |||
|         std::size_t navMeshCacheSize = 0; | ||||
|         std::size_t usedNavMeshTiles = 0; | ||||
|         std::size_t cachedNavMeshTiles = 0; | ||||
|         std::size_t hitCount = 0; | ||||
|         std::size_t getCount = 0; | ||||
| 
 | ||||
|         { | ||||
|             const std::lock_guard<std::mutex> lock(mMutex); | ||||
|             navMeshCacheSize = mUsedNavMeshDataSize; | ||||
|             usedNavMeshTiles = mBusyItems.size(); | ||||
|             cachedNavMeshTiles = mFreeItems.size(); | ||||
|             hitCount = mHitCount; | ||||
|             getCount = mGetCount; | ||||
|         } | ||||
| 
 | ||||
|         stats.setAttribute(frameNumber, "NavMesh CacheSize", navMeshCacheSize); | ||||
|         stats.setAttribute(frameNumber, "NavMesh UsedTiles", usedNavMeshTiles); | ||||
|         stats.setAttribute(frameNumber, "NavMesh CachedTiles", cachedNavMeshTiles); | ||||
|         stats.setAttribute(frameNumber, "NavMesh CacheHitRate", static_cast<double>(hitCount) / getCount * 100.0); | ||||
|     } | ||||
| 
 | ||||
|     void NavMeshTilesCache::removeLeastRecentlyUsed() | ||||
|  | @ -152,8 +127,8 @@ namespace DetourNavigator | |||
|         if (value == tileValues->second.mMap.end()) | ||||
|             return; | ||||
| 
 | ||||
|         mUsedNavMeshDataSize -= getSize(item); | ||||
|         mFreeNavMeshDataSize -= getSize(item); | ||||
|         mUsedNavMeshDataSize -= item.mSize; | ||||
|         mFreeNavMeshDataSize -= item.mSize; | ||||
| 
 | ||||
|         tileValues->second.mMap.erase(value); | ||||
|         mFreeItems.pop_back(); | ||||
|  | @ -174,7 +149,7 @@ namespace DetourNavigator | |||
|             return; | ||||
| 
 | ||||
|         mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator); | ||||
|         mFreeNavMeshDataSize -= getSize(*iterator); | ||||
|         mFreeNavMeshDataSize -= iterator->mSize; | ||||
|     } | ||||
| 
 | ||||
|     void NavMeshTilesCache::releaseItem(ItemIterator iterator) | ||||
|  | @ -185,71 +160,6 @@ namespace DetourNavigator | |||
|         const std::lock_guard<std::mutex> lock(mMutex); | ||||
| 
 | ||||
|         mFreeItems.splice(mFreeItems.begin(), mBusyItems, iterator); | ||||
|         mFreeNavMeshDataSize += getSize(*iterator); | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|         mFreeNavMeshDataSize += iterator->mSize; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -27,6 +27,89 @@ namespace DetourNavigator | |||
|         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 | ||||
|     { | ||||
|     public: | ||||
|  | @ -35,14 +118,16 @@ namespace DetourNavigator | |||
|             std::atomic<std::int64_t> mUseCount; | ||||
|             osg::Vec3f mAgentHalfExtents; | ||||
|             TilePosition mChangedTile; | ||||
|             std::vector<unsigned char> mNavMeshKey; | ||||
|             NavMeshKey mNavMeshKey; | ||||
|             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) | ||||
|                 , mAgentHalfExtents(agentHalfExtents) | ||||
|                 , 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; | ||||
| 
 | ||||
|     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 | ||||
|         { | ||||
|             std::map<KeyView, ItemIterator> mMap; | ||||
|             std::map<NavMeshKeyRef, ItemIterator, std::less<>> mMap; | ||||
|         }; | ||||
| 
 | ||||
|         mutable std::mutex mMutex; | ||||
|         std::size_t mMaxNavMeshDataSize; | ||||
|         std::size_t mUsedNavMeshDataSize; | ||||
|         std::size_t mFreeNavMeshDataSize; | ||||
|         std::size_t mHitCount; | ||||
|         std::size_t mGetCount; | ||||
|         std::list<Item> mBusyItems; | ||||
|         std::list<Item> mFreeItems; | ||||
|         std::map<osg::Vec3f, std::map<TilePosition, TileMap>> mValues; | ||||
|  | @ -203,11 +220,6 @@ namespace DetourNavigator | |||
|         void acquireItemUnsafe(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 <tuple> | ||||
| 
 | ||||
| namespace DetourNavigator | ||||
| { | ||||
|     struct OffMeshConnection | ||||
|  | @ -13,6 +15,11 @@ namespace DetourNavigator | |||
|         osg::Vec3f mEnd; | ||||
|         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 | ||||
|  |  | |||
|  | @ -85,6 +85,8 @@ namespace DetourNavigator | |||
|                     std::for_each(byId.first, byId.second, [&] (const auto& v) { result.push_back(v.second); }); | ||||
|                 }); | ||||
| 
 | ||||
|             std::sort(result.begin(), result.end()); | ||||
| 
 | ||||
|             return result; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,9 +5,12 @@ | |||
| #include "chunkytrimesh.hpp" | ||||
| #include "bounds.hpp" | ||||
| 
 | ||||
| #include <components/bullethelpers/operators.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <tuple> | ||||
| 
 | ||||
| #include <osg/Vec3f> | ||||
| 
 | ||||
|  | @ -87,6 +90,17 @@ namespace DetourNavigator | |||
|         ChunkyTriMesh mChunkyTriMesh; | ||||
|         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 | ||||
|  |  | |||
|  | @ -155,6 +155,7 @@ namespace DetourNavigator | |||
|     std::shared_ptr<RecastMesh> RecastMeshBuilder::create(std::size_t generation, std::size_t revision) | ||||
|     { | ||||
|         optimizeRecastMesh(mIndices, mVertices); | ||||
|         std::sort(mWater.begin(), mWater.end()); | ||||
|         return std::make_shared<RecastMesh>(generation, revision, mIndices, mVertices, mAreaTypes, | ||||
|             mWater, mSettings.get().mTrianglesPerChunk); | ||||
|     } | ||||
|  |  | |||
|  | @ -394,6 +394,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) | |||
|             "NavMesh CacheSize", | ||||
|             "NavMesh UsedTiles", | ||||
|             "NavMesh CachedTiles", | ||||
|             "NavMesh CacheHitRate", | ||||
|             "", | ||||
|             "Mechanics Actors", | ||||
|             "Mechanics Objects", | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue