From 71b52046e07f957c4022d15be5ab54fd86100b70 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sun, 8 Feb 2026 22:08:42 -0800 Subject: [PATCH] Keep M2 models permanently in VRAM to eliminate loading hitches Modern GPUs have 8-16GB VRAM - leverage this to cache all M2 models permanently. Changes: - Disabled cleanupUnusedModels() call when tiles unload - Models now stay in VRAM after initial load, even when tiles unload - Increased taxi mounting delay from 3s to 5s for more precache time - Added logging: M2 model count, instance count, and GPU upload duration - Added debug logging when M2 models are uploaded per tile This fixes the "building pops up then pause" issue - models were being: 1. Loaded when tile loads 2. Unloaded when tile unloads (behind taxi) 3. Re-loaded when flying through again (causing hitch) Now models persist in VRAM permanently (few hundred MB for typical session). First pass loads to VRAM, subsequent passes are instant. --- src/core/application.cpp | 10 ++++++++-- src/game/game_handler.cpp | 6 +++--- src/rendering/terrain_manager.cpp | 24 +++++++++++++++--------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index 65150b94..bf15f228 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -731,9 +731,15 @@ void Application::setupUICallbacks() { // Taxi flight start callback - upload all precached tiles to GPU before flight begins gameHandler->setTaxiFlightStartCallback([this]() { - if (renderer && renderer->getTerrainManager()) { - LOG_INFO("Uploading all precached tiles to GPU before taxi flight..."); + if (renderer && renderer->getTerrainManager() && renderer->getM2Renderer()) { + LOG_INFO("Uploading all precached tiles (terrain + M2 models) to GPU before taxi flight..."); + auto start = std::chrono::steady_clock::now(); renderer->getTerrainManager()->processAllReadyTiles(); + auto end = std::chrono::steady_clock::now(); + auto durationMs = std::chrono::duration_cast(end - start).count(); + uint32_t m2Count = renderer->getM2Renderer()->getModelCount(); + uint32_t instCount = renderer->getM2Renderer()->getInstanceCount(); + LOG_INFO("GPU upload completed in ", durationMs, "ms - ", m2Count, " M2 models in VRAM (", instCount, " instances)"); } }); diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index dfc61b02..299f35dd 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -262,11 +262,11 @@ void GameHandler::update(float deltaTime) { } } - // Mounting delay for taxi (terrain precache time) + // Mounting delay for taxi (terrain + M2 model precache time) if (taxiMountingDelay_) { taxiMountingTimer_ += deltaTime; - // 3 second delay for "mounting" animation and terrain precache - if (taxiMountingTimer_ >= 3.0f) { + // 5 second delay for terrain and M2 models to load and upload to VRAM + if (taxiMountingTimer_ >= 5.0f) { taxiMountingDelay_ = false; taxiMountingTimer_ = 0.0f; // Upload all precached tiles to GPU before flight starts diff --git a/src/rendering/terrain_manager.cpp b/src/rendering/terrain_manager.cpp index 10959c64..014628be 100644 --- a/src/rendering/terrain_manager.cpp +++ b/src/rendering/terrain_manager.cpp @@ -528,13 +528,16 @@ void TerrainManager::finalizeTile(const std::shared_ptr& pending) { m2Renderer->initialize(assetManager); } - // Upload unique models + // Upload unique M2 models to GPU (stays in VRAM permanently until shutdown) std::unordered_set uploadedModelIds; for (auto& m2Ready : pending->m2Models) { if (m2Renderer->loadModel(m2Ready.model, m2Ready.modelId)) { uploadedModelIds.insert(m2Ready.modelId); } } + if (!uploadedModelIds.empty()) { + LOG_DEBUG(" Uploaded ", uploadedModelIds.size(), " unique M2 models to VRAM for tile [", x, ",", y, "]"); + } // Create instances (deduplicate by uniqueId across tile boundaries) int loadedDoodads = 0; @@ -1202,16 +1205,19 @@ void TerrainManager::streamTiles() { } if (!tilesToUnload.empty()) { - // Clean up models that lost all instances (once, after all tiles removed) - if (m2Renderer) { - m2Renderer->cleanupUnusedModels(); - } - if (wmoRenderer) { - wmoRenderer->cleanupUnusedModels(); - } + // Don't clean up models during streaming - keep them in VRAM for performance + // Modern GPUs have 8-16GB VRAM, models are only ~hundreds of MB + // Cleanup can be done manually when memory pressure is detected + // NOTE: Disabled permanent model cleanup to leverage modern VRAM capacity + // if (m2Renderer) { + // m2Renderer->cleanupUnusedModels(); + // } + // if (wmoRenderer) { + // wmoRenderer->cleanupUnusedModels(); + // } LOG_INFO("Unloaded ", tilesToUnload.size(), " distant tiles, ", - loadedTiles.size(), " remain"); + loadedTiles.size(), " remain (models kept in VRAM)"); } }