From 93f873b521363bada1380f8e62d5c0d8d7bc9e89 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 23 Feb 2026 06:51:06 -0800 Subject: [PATCH] Allow texture load retries instead of permanently caching failures Remove negative cache for transient load failures in M2, terrain, and character renderers. Failed textures return white and will be retried on next model/tile load when assets may have finished streaming. --- include/rendering/character_renderer.hpp | 3 ++- src/rendering/character_renderer.cpp | 13 ++++--------- src/rendering/m2_renderer.cpp | 10 +++------- src/rendering/terrain_renderer.cpp | 10 ++-------- 4 files changed, 11 insertions(+), 25 deletions(-) diff --git a/include/rendering/character_renderer.hpp b/include/rendering/character_renderer.hpp index e324622e..2c73129a 100644 --- a/include/rendering/character_renderer.hpp +++ b/include/rendering/character_renderer.hpp @@ -264,7 +264,8 @@ private: std::unordered_map textureHasAlphaByPtr_; std::unordered_map textureColorKeyBlackByPtr_; std::unordered_map compositeCache_; // key → texture for reuse - std::unordered_set failedTextureCache_; // negative cache for missing textures + std::unordered_set failedTextureCache_; // negative cache for budget exhaustion + std::unordered_set loggedTextureLoadFails_; // dedup warning logs size_t textureCacheBytes_ = 0; uint64_t textureCacheCounter_ = 0; size_t textureCacheBudgetBytes_ = 1024ull * 1024 * 1024; diff --git a/src/rendering/character_renderer.cpp b/src/rendering/character_renderer.cpp index c9155a16..ad5b0868 100644 --- a/src/rendering/character_renderer.cpp +++ b/src/rendering/character_renderer.cpp @@ -526,17 +526,12 @@ VkTexture* CharacterRenderer::loadTexture(const std::string& path) { return whiteTexture_.get(); } - // Check negative cache to avoid repeated file I/O for textures that don't exist - if (failedTextureCache_.count(key)) { - return whiteTexture_.get(); - } - auto blpImage = assetManager->loadTexture(key); if (!blpImage.isValid()) { - static constexpr size_t kMaxFailedTextureCache = 200000; - core::Logger::getInstance().warning("Failed to load texture: ", path); - if (failedTextureCache_.size() < kMaxFailedTextureCache) { - failedTextureCache_.insert(key); + // Return white fallback but don't cache the failure — allow retry + // on next character load in case the asset becomes available. + if (loggedTextureLoadFails_.insert(key).second) { + core::Logger::getInstance().warning("Failed to load texture: ", path); } return whiteTexture_.get(); } diff --git a/src/rendering/m2_renderer.cpp b/src/rendering/m2_renderer.cpp index 8d189950..f41390f3 100644 --- a/src/rendering/m2_renderer.cpp +++ b/src/rendering/m2_renderer.cpp @@ -3342,9 +3342,7 @@ VkTexture* M2Renderer::loadTexture(const std::string& path, uint32_t texFlags) { it->second.lastUse = ++textureCacheCounter_; return it->second.texture.get(); } - if (failedTextureCache_.count(key)) { - return whiteTexture_.get(); - } + // No negative cache check — allow retries for transiently missing textures auto containsToken = [](const std::string& haystack, const char* token) { return haystack.find(token) != std::string::npos; @@ -3365,10 +3363,8 @@ VkTexture* M2Renderer::loadTexture(const std::string& path, uint32_t texFlags) { // Load BLP texture pipeline::BLPImage blp = assetManager->loadTexture(key); if (!blp.isValid()) { - static constexpr size_t kMaxFailedTextureCache = 200000; - if (failedTextureCache_.size() < kMaxFailedTextureCache) { - failedTextureCache_.insert(key); - } + // Return white fallback but don't cache the failure — MPQ reads can + // fail transiently during streaming; allow retry on next model load. if (loggedTextureLoadFails_.insert(key).second) { LOG_WARNING("M2: Failed to load texture: ", path); } diff --git a/src/rendering/terrain_renderer.cpp b/src/rendering/terrain_renderer.cpp index 67770dfd..208ae25b 100644 --- a/src/rendering/terrain_renderer.cpp +++ b/src/rendering/terrain_renderer.cpp @@ -442,16 +442,10 @@ VkTexture* TerrainRenderer::loadTexture(const std::string& path) { it->second.lastUse = ++textureCacheCounter_; return it->second.texture.get(); } - if (failedTextureCache_.count(key)) { - return whiteTexture.get(); - } - pipeline::BLPImage blp = assetManager->loadTexture(key); if (!blp.isValid()) { - static constexpr size_t kMaxFailedTextureCache = 200000; - if (failedTextureCache_.size() < kMaxFailedTextureCache) { - failedTextureCache_.insert(key); - } + // Return white fallback but don't cache the failure — allow retry + // on next tile load in case the asset becomes available. if (loggedTextureLoadFails_.insert(key).second) { LOG_WARNING("Failed to load texture: ", path); }