1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 08:39:45 +00:00

Merge pull request #2243 from elsid/navmesh_tile_cache_optimization

Navmesh tile cache optimization
This commit is contained in:
Bret Curtis 2019-03-11 07:50:30 +01:00 committed by GitHub
commit c89734974c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 116 additions and 8 deletions

View file

@ -1,6 +1,8 @@
#include "navmeshtilescache.hpp"
#include "exceptions.hpp"
#include <cstring>
namespace DetourNavigator
{
namespace
@ -61,8 +63,7 @@ namespace DetourNavigator
if (tileValues == agentValues->second.end())
return Value();
// TODO: use different function to make key to avoid unnecessary std::string allocation
const auto tile = tileValues->second.mMap.find(makeNavMeshKey(recastMesh, offMeshConnections));
const auto tile = tileValues->second.mMap.find(RecastMeshKeyView(recastMesh, offMeshConnections));
if (tile == tileValues->second.mMap.end())
return Value();
@ -85,7 +86,7 @@ namespace DetourNavigator
if (navMeshSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize))
return Value();
const auto navMeshKey = makeNavMeshKey(recastMesh, offMeshConnections);
auto navMeshKey = makeNavMeshKey(recastMesh, offMeshConnections);
const auto itemSize = navMeshSize + 2 * navMeshKey.size();
if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize))
@ -94,9 +95,8 @@ namespace DetourNavigator
while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize)
removeLeastRecentlyUsed();
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, navMeshKey);
// TODO: use std::string_view or some alternative to avoid navMeshKey copy into both mFreeItems and mValues
const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(navMeshKey, iterator);
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(navMeshKey));
const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(iterator->mNavMeshKey, iterator);
if (!emplaced.second)
{
@ -131,9 +131,10 @@ namespace DetourNavigator
mUsedNavMeshDataSize -= getSize(item);
mFreeNavMeshDataSize -= getSize(item);
mFreeItems.pop_back();
tileValues->second.mMap.erase(value);
mFreeItems.pop_back();
if (!tileValues->second.mMap.empty())
return;
@ -163,4 +164,58 @@ namespace DetourNavigator
mFreeItems.splice(mFreeItems.begin(), mBusyItems, iterator);
mFreeNavMeshDataSize += getSize(*iterator);
}
namespace
{
struct CompareBytes
{
const char* mRhsIt;
const char* 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);
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::string& 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;
}
}

View file

@ -10,6 +10,7 @@
#include <map>
#include <list>
#include <mutex>
#include <cassert>
namespace DetourNavigator
{
@ -105,10 +106,62 @@ namespace DetourNavigator
NavMeshData&& value);
private:
class KeyView
{
public:
KeyView() = default;
KeyView(const std::string& value)
: mValue(&value) {}
const std::string& getValue() const
{
assert(mValue);
return *mValue;
}
virtual int compare(const std::string& other) const
{
assert(mValue);
return mValue->compare(other);
}
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::string* mValue = nullptr;
};
class RecastMeshKeyView : public KeyView
{
public:
RecastMeshKeyView(const RecastMesh& recastMesh, const std::vector<OffMeshConnection>& offMeshConnections)
: mRecastMesh(recastMesh), mOffMeshConnections(offMeshConnections) {}
int compare(const std::string& other) const override;
bool isLess(const KeyView& other) const override
{
return compare(other.getValue()) < 0;
}
private:
std::reference_wrapper<const RecastMesh> mRecastMesh;
std::reference_wrapper<const std::vector<OffMeshConnection>> mOffMeshConnections;
};
struct TileMap
{
std::map<std::string, ItemIterator> mMap;
std::map<KeyView, ItemIterator> mMap;
};
std::mutex mMutex;