From 266b54560ed1d5e1f60a72714943b29561cbbf2a Mon Sep 17 00:00:00 2001 From: hydrogendeuteride Date: Mon, 3 Nov 2025 18:44:42 +0900 Subject: [PATCH] ADD: Texture Cache 2 --- src/core/texture_cache.cpp | 45 ++++++++++++++++++++++----- src/render/vk_renderpass_geometry.cpp | 16 ++++++++++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/core/texture_cache.cpp b/src/core/texture_cache.cpp index a239bde..d89dc00 100644 --- a/src/core/texture_cache.cpp +++ b/src/core/texture_cache.cpp @@ -34,7 +34,23 @@ void TextureCache::cleanup() TextureCache::TextureHandle TextureCache::request(const TextureKey &key, VkSampler sampler) { - auto it = _lookup.find(key.hash); + // Ensure we have a valid, stable hash for deduplication. + TextureKey normKey = key; + if (normKey.hash == 0) + { + if (normKey.kind == TextureKey::SourceKind::FilePath) + { + std::string id = std::string("PATH:") + normKey.path + (normKey.srgb ? "#sRGB" : "#UNORM"); + normKey.hash = texcache::fnv1a64(id); + } + else if (!normKey.bytes.empty()) + { + uint64_t h = texcache::fnv1a64(normKey.bytes.data(), normKey.bytes.size()); + normKey.hash = h ^ (normKey.srgb ? 0x9E3779B97F4A7C15ull : 0ull); + } + } + + auto it = _lookup.find(normKey.hash); if (it != _lookup.end()) { TextureHandle h = it->second; @@ -47,19 +63,19 @@ TextureCache::TextureHandle TextureCache::request(const TextureKey &key, VkSampl } TextureHandle h = static_cast(_entries.size()); - _lookup.emplace(key.hash, h); + _lookup.emplace(normKey.hash, h); Entry e{}; - e.key = key; + e.key = normKey; e.sampler = sampler; e.state = EntryState::Unloaded; - if (key.kind == TextureKey::SourceKind::FilePath) + if (normKey.kind == TextureKey::SourceKind::FilePath) { - e.path = key.path; + e.path = normKey.path; } else { - e.bytes = key.bytes; + e.bytes = normKey.bytes; } _entries.push_back(std::move(e)); return h; @@ -198,12 +214,25 @@ void TextureCache::pumpLoads(ResourceManager &rm, FrameResources &) // Simple throttle to avoid massive spikes. const int kMaxLoadsPerPump = 4; int started = 0; + const uint32_t now = _context ? _context->frameIndex : 0u; for (auto &e : _entries) { if (e.state == EntryState::Unloaded) { - start_load(e, rm); - if (++started >= kMaxLoadsPerPump) break; + // Visibility-driven residency: only start uploads for textures + // that were marked used recently (current or previous frame). + // This avoids uploading assets that are not visible. + bool recentlyUsed = true; + if (_context) + { + // Schedule when first seen (previous frame) or if seen again. + recentlyUsed = (now == 0u) || (now - e.lastUsedFrame <= 1u); + } + if (recentlyUsed) + { + start_load(e, rm); + if (++started >= kMaxLoadsPerPump) break; + } } } } diff --git a/src/render/vk_renderpass_geometry.cpp b/src/render/vk_renderpass_geometry.cpp index fdbcb47..b14f70a 100644 --- a/src/render/vk_renderpass_geometry.cpp +++ b/src/render/vk_renderpass_geometry.cpp @@ -170,6 +170,22 @@ void GeometryPass::draw_geometry(VkCommandBuffer cmd, } } + // Texture visibility-driven residency + if (ctxLocal->textures && !opaque_draws.empty()) + { + std::unordered_set seen; + seen.reserve(opaque_draws.size()); + for (uint32_t idx : opaque_draws) + { + const RenderObject &r = mainDrawContext.OpaqueSurfaces[idx]; + VkDescriptorSet set = r.material ? r.material->materialSet : VK_NULL_HANDLE; + if (set != VK_NULL_HANDLE && seen.insert(set).second) + { + ctxLocal->textures->markSetUsed(set, ctxLocal->frameIndex); + } + } + } + std::sort(opaque_draws.begin(), opaque_draws.end(), [&](const auto &iA, const auto &iB) { const RenderObject &A = mainDrawContext.OpaqueSurfaces[iA];