Add dynamic memory-based asset caching and aggressive loading

- Add MemoryMonitor class for dynamic cache sizing based on available RAM
- Increase terrain load radius to 8 tiles (17x17 grid, 289 tiles)
- Scale worker threads to 75% of logical cores (no cap)
- Increase cache budget to 80% of available RAM, max file size to 50%
- Increase M2 render distance: 1200 units during taxi, 800 when >2000 instances
- Fix camera positioning during taxi flights (external follow mode)
- Add 2-second landing cooldown to prevent re-entering taxi mode on lag
- Update interval reduced to 33ms for faster streaming responsiveness

Optimized for high-memory systems while scaling gracefully to lower-end hardware.
Cache and render distances now fully utilize available VRAM on minimum spec GPUs.
This commit is contained in:
Kelsi 2026-02-08 23:15:26 -08:00
parent 27d0496894
commit c047446fb7
12 changed files with 198 additions and 19 deletions

View file

@ -5,6 +5,7 @@
#include "rendering/wmo_renderer.hpp"
#include "rendering/camera.hpp"
#include "core/coordinates.hpp"
#include "core/memory_monitor.hpp"
#include "pipeline/asset_manager.hpp"
#include "pipeline/adt_loader.hpp"
#include "pipeline/m2_loader.hpp"
@ -113,10 +114,21 @@ bool TerrainManager::initialize(pipeline::AssetManager* assets, TerrainRenderer*
return false;
}
// Start background worker pool
// Set dynamic tile cache budget (use other half of recommended budget)
auto& memMonitor = core::MemoryMonitor::getInstance();
tileCacheBudgetBytes_ = memMonitor.getRecommendedCacheBudget() / 2;
LOG_INFO("Terrain tile cache budget: ", tileCacheBudgetBytes_ / (1024 * 1024), " MB (dynamic)");
// Start background worker pool (dynamic: scales with available cores)
// Use 75% of logical cores for decompression, leaving headroom for render/OS
workerRunning.store(true);
unsigned hc = std::thread::hardware_concurrency();
workerCount = static_cast<int>(hc > 0 ? std::min(4u, std::max(2u, hc - 1)) : 2u);
if (hc > 0) {
unsigned targetWorkers = std::max(6u, (hc * 3) / 4); // 75% of cores, minimum 6
workerCount = static_cast<int>(targetWorkers);
} else {
workerCount = 6; // Fallback
}
workerThreads.reserve(workerCount);
for (int i = 0; i < workerCount; i++) {
workerThreads.emplace_back(&TerrainManager::workerLoop, this);
@ -917,10 +929,16 @@ void TerrainManager::unloadAll() {
m2Renderer->clear();
}
// Restart worker threads so streaming can resume
// Restart worker threads so streaming can resume (dynamic: scales with available cores)
// Use 75% of logical cores for decompression, leaving headroom for render/OS
workerRunning.store(true);
unsigned hc = std::thread::hardware_concurrency();
workerCount = static_cast<int>(hc > 0 ? std::min(4u, std::max(2u, hc - 1)) : 2u);
if (hc > 0) {
unsigned targetWorkers = std::max(6u, (hc * 3) / 4); // 75% of cores, minimum 6
workerCount = static_cast<int>(targetWorkers);
} else {
workerCount = 6; // Fallback
}
workerThreads.reserve(workerCount);
for (int i = 0; i < workerCount; i++) {
workerThreads.emplace_back(&TerrainManager::workerLoop, this);