perf: eliminate ~70 unnecessary sqrt ops per frame, optimize caches and threading

Squared distance optimizations across 30 files:
- Convert glm::length() comparisons to glm::dot() (no sqrt)
- Use glm::inversesqrt() for check-then-normalize patterns (1 rsqrt vs 2 sqrt)
- Defer sqrt to after early-out checks in collision/movement code
- Hottest paths: camera_controller (21), weather particles, WMO collision,
  transport movement, creature interpolation, nameplate culling

Container and algorithm improvements:
- std::map<string> → std::unordered_map for asset/DBC/MPQ/warden caches
- std::mutex → std::shared_mutex for asset_manager and mpq_manager caches
- std::sort → std::partial_sort in lighting_manager (top-2 of N volumes)
- Double-lookup find()+operator[] → insert_or_assign in game_handler
- Add reserve() for per-frame vectors: weather, swim_effects, WMO/M2 collision

Threading and synchronization:
- Replace 1ms busy-wait polling with condition_variable in character_renderer
- Move timestamp capture before mutex in logger
- Use memory_order_acquire/release for normal map completion signaling

API additions:
- DBC getStringView()/getStringViewByOffset() for zero-copy string access
- Parse creature display IDs from SMSG_CREATURE_QUERY_SINGLE_RESPONSE
This commit is contained in:
Kelsi 2026-03-27 16:33:16 -07:00
parent cf0e2aa240
commit b0466e9029
29 changed files with 328 additions and 196 deletions

View file

@ -396,14 +396,15 @@ std::vector<uint8_t> AssetManager::readFile(const std::string& path) const {
std::string normalized = normalizePath(path);
// Check cache first
// Check cache first (shared lock allows concurrent reads)
{
std::lock_guard<std::mutex> cacheLock(cacheMutex);
std::shared_lock<std::shared_mutex> cacheLock(cacheMutex);
auto it = fileCache.find(normalized);
if (it != fileCache.end()) {
it->second.lastAccessTime = ++fileCacheAccessCounter;
auto data = it->second.data;
cacheLock.unlock();
fileCacheHits++;
return it->second.data;
return data;
}
}
@ -422,7 +423,7 @@ std::vector<uint8_t> AssetManager::readFile(const std::string& path) const {
// Add to cache if within budget
size_t fileSize = data.size();
if (fileSize > 0 && fileSize < fileCacheBudget / 2) {
std::lock_guard<std::mutex> cacheLock(cacheMutex);
std::lock_guard<std::shared_mutex> cacheLock(cacheMutex);
// Evict old entries if needed (LRU)
while (fileCacheTotalBytes + fileSize > fileCacheBudget && !fileCache.empty()) {
auto lru = fileCache.begin();
@ -456,13 +457,13 @@ std::vector<uint8_t> AssetManager::readFileOptional(const std::string& path) con
}
void AssetManager::clearDBCCache() {
std::lock_guard<std::mutex> lock(cacheMutex);
std::lock_guard<std::shared_mutex> lock(cacheMutex);
dbcCache.clear();
LOG_INFO("Cleared DBC cache");
}
void AssetManager::clearCache() {
std::lock_guard<std::mutex> lock(cacheMutex);
std::lock_guard<std::shared_mutex> lock(cacheMutex);
dbcCache.clear();
fileCache.clear();
fileCacheTotalBytes = 0;