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:
commit
c89734974c
2 changed files with 116 additions and 8 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue