memory bug fixed-/vk_engine_ui.cpp, vk_loader.h

This commit is contained in:
2025-11-22 18:37:12 +09:00
parent cec2dadd94
commit b023907df8
6 changed files with 137 additions and 6 deletions

View File

@@ -42,10 +42,15 @@ void TextureCache::cleanup()
} }
if (!_context || !_context->getResources()) return; if (!_context || !_context->getResources()) return;
auto *rm = _context->getResources(); auto *rm = _context->getResources();
for (auto &e : _entries) for (TextureHandle h = 0; h < _entries.size(); ++h)
{ {
auto &e = _entries[h];
if (e.state == EntryState::Resident && e.image.image) if (e.state == EntryState::Resident && e.image.image)
{ {
fmt::println("[TextureCache] cleanup destroy handle={} path='{}' bytes={}",
h,
e.path.empty() ? "<bytes>" : e.path,
e.sizeBytes);
rm->destroy_image(e.image); rm->destroy_image(e.image);
e.image = {}; e.image = {};
} }
@@ -102,6 +107,13 @@ TextureCache::TextureHandle TextureCache::request(const TextureKey &key, VkSampl
e.bytes = normKey.bytes; e.bytes = normKey.bytes;
_cpuSourceBytes += e.bytes.size(); _cpuSourceBytes += e.bytes.size();
} }
fmt::println("[TextureCache] request handle={} kind={} path='{}' srgb={} mipmapped={} hash=0x{:016x}",
h,
(normKey.kind == TextureKey::SourceKind::FilePath ? "FilePath" : "Bytes"),
normKey.kind == TextureKey::SourceKind::FilePath ? normKey.path : "<bytes>",
normKey.srgb,
normKey.mipmapped,
normKey.hash);
_entries.push_back(std::move(e)); _entries.push_back(std::move(e));
return h; return h;
} }
@@ -386,6 +398,11 @@ void TextureCache::evictToBudget(size_t budgetBytes)
// Rewrite watchers back to fallback before destroying // Rewrite watchers back to fallback before destroying
patch_to_fallback(e); patch_to_fallback(e);
fmt::println("[TextureCache] evictToBudget destroy handle={} path='{}' bytes={} residentBytesBefore={}",
h,
e.path.empty() ? "<bytes>" : e.path,
e.sizeBytes,
_residentBytes);
_context->getResources()->destroy_image(e.image); _context->getResources()->destroy_image(e.image);
e.image = {}; e.image = {};
e.state = EntryState::Evicted; e.state = EntryState::Evicted;
@@ -720,6 +737,14 @@ size_t TextureCache::drain_ready_uploads(ResourceManager &rm, size_t budgetBytes
{ {
levels.push_back(ResourceManager::MipLevelCopy{ lv.offset, lv.length, lv.width, lv.height }); levels.push_back(ResourceManager::MipLevelCopy{ lv.offset, lv.length, lv.width, lv.height });
} }
fmt::println("[TextureCache] upload KTX2 handle={} fmt={} levels={} size={}x{} srgb={} path='{}'",
res.handle,
string_VkFormat(fmt),
res.ktxMipLevels,
extent.width,
extent.height,
res.srgb,
e.path);
e.image = rm.create_image_compressed(res.ktx.bytes.data(), res.ktx.bytes.size(), fmt, levels); e.image = rm.create_image_compressed(res.ktx.bytes.data(), res.ktx.bytes.size(), fmt, levels);
e.sizeBytes = expectedBytes; e.sizeBytes = expectedBytes;
} }
@@ -757,6 +782,14 @@ size_t TextureCache::drain_ready_uploads(ResourceManager &rm, size_t budgetBytes
} }
uint32_t mipOverride = (res.mipmapped ? desiredLevels : 1); uint32_t mipOverride = (res.mipmapped ? desiredLevels : 1);
fmt::println("[TextureCache] upload raster handle={} fmt={} levels={} size={}x{} srgb={} path='{}'",
res.handle,
string_VkFormat(fmt),
mipOverride,
extent.width,
extent.height,
res.srgb,
e.path);
e.image = rm.create_image(src, extent, fmt, VK_IMAGE_USAGE_SAMPLED_BIT, res.mipmapped, mipOverride); e.image = rm.create_image(src, extent, fmt, VK_IMAGE_USAGE_SAMPLED_BIT, res.mipmapped, mipOverride);
e.sizeBytes = expectedBytes; e.sizeBytes = expectedBytes;
} }
@@ -847,10 +880,16 @@ bool TextureCache::try_make_space(size_t bytesNeeded, uint32_t now)
for (auto &pair : order) for (auto &pair : order)
{ {
if (freed >= bytesNeeded) break; if (freed >= bytesNeeded) break;
Entry &e = _entries[pair.first]; TextureHandle h = pair.first;
Entry &e = _entries[h];
if (e.state != EntryState::Resident) continue; if (e.state != EntryState::Resident) continue;
patch_to_fallback(e); patch_to_fallback(e);
fmt::println("[TextureCache] try_make_space destroy handle={} path='{}' bytes={} residentBytesBefore={}",
h,
e.path.empty() ? "<bytes>" : e.path,
e.sizeBytes,
_residentBytes);
_context->getResources()->destroy_image(e.image); _context->getResources()->destroy_image(e.image);
e.image = {}; e.image = {};
e.state = EntryState::Evicted; e.state = EntryState::Evicted;

View File

@@ -620,8 +620,44 @@ namespace
else if (pick->ownerType == RenderObject::OwnerType::GLTFInstance) else if (pick->ownerType == RenderObject::OwnerType::GLTFInstance)
{ {
bool ok = eng->_sceneManager->removeGLTFInstance(pick->ownerName); bool ok = eng->_sceneManager->removeGLTFInstance(pick->ownerName);
deleteStatus = ok ? "Removed glTF instance: " + pick->ownerName if (ok)
: "glTF instance not found: " + pick->ownerName; {
deleteStatus = "Removed glTF instance: " + pick->ownerName;
// Debug: log and clear any picks that still reference the deleted instance.
fmt::println("[Debug] GLTF delete requested for '{}'; clearing picks if they match.",
pick->ownerName);
if (eng->_lastPick.valid &&
eng->_lastPick.ownerType == RenderObject::OwnerType::GLTFInstance &&
eng->_lastPick.ownerName == pick->ownerName)
{
fmt::println("[Debug] Clearing _lastPick for deleted GLTF instance '{}'", pick->ownerName);
eng->_lastPick.valid = false;
eng->_lastPick.ownerName.clear();
eng->_lastPick.ownerType = RenderObject::OwnerType::None;
eng->_lastPick.mesh = nullptr;
eng->_lastPick.scene = nullptr;
eng->_lastPick.node = nullptr;
}
if (eng->_hoverPick.valid &&
eng->_hoverPick.ownerType == RenderObject::OwnerType::GLTFInstance &&
eng->_hoverPick.ownerName == pick->ownerName)
{
fmt::println("[Debug] Clearing _hoverPick for deleted GLTF instance '{}'", pick->ownerName);
eng->_hoverPick.valid = false;
eng->_hoverPick.ownerName.clear();
eng->_hoverPick.ownerType = RenderObject::OwnerType::None;
eng->_hoverPick.mesh = nullptr;
eng->_hoverPick.scene = nullptr;
eng->_hoverPick.node = nullptr;
}
}
else
{
deleteStatus = "glTF instance not found: " + pick->ownerName;
}
} }
else else
{ {

View File

@@ -164,7 +164,7 @@ VkSamplerMipmapMode extract_mipmap_mode(fastgltf::Filter filter)
std::optional<std::shared_ptr<LoadedGLTF> > loadGltf(VulkanEngine *engine, std::string_view filePath) std::optional<std::shared_ptr<LoadedGLTF> > loadGltf(VulkanEngine *engine, std::string_view filePath)
{ {
//> load_1 //> load_1
fmt::print("Loading GLTF: {}", filePath); fmt::println("[GLTF] loadGltf begin: '{}'", filePath);
std::shared_ptr<LoadedGLTF> scene = std::make_shared<LoadedGLTF>(); std::shared_ptr<LoadedGLTF> scene = std::make_shared<LoadedGLTF>();
scene->creator = engine; scene->creator = engine;
@@ -849,6 +849,13 @@ std::optional<std::shared_ptr<LoadedGLTF> > loadGltf(VulkanEngine *engine, std::
} }
}, img.data); }, img.data);
} }
fmt::println("[GLTF] loadGltf done: meshes={} materials={} images={} samplers={} animations={} debugName='{}'",
file.meshes.size(),
file.materials.size(),
file.images.size(),
file.samplers.size(),
file.animations.size(),
file.debugName.empty() ? "<none>" : file.debugName);
return scene; return scene;
//< load_graph //< load_graph
} }
@@ -1050,6 +1057,14 @@ void LoadedGLTF::updateAnimation(float dt)
void LoadedGLTF::clearAll() void LoadedGLTF::clearAll()
{ {
const char *name = debugName.empty() ? "<unnamed>" : debugName.c_str();
fmt::println("[GLTF] clearAll begin for '{}' (meshes={} images={} materials={} samplers={})",
name,
meshes.size(),
images.size(),
materials.size(),
samplers.size());
VkDevice dv = creator->_deviceManager->device(); VkDevice dv = creator->_deviceManager->device();
// Before destroying descriptor pools, unregister descriptor-set watches so // Before destroying descriptor pools, unregister descriptor-set watches so
@@ -1097,4 +1112,11 @@ void LoadedGLTF::clearAll()
descriptorPool.destroy_pools(dv); descriptorPool.destroy_pools(dv);
creator->_resourceManager->destroy_buffer(materialBuffer); creator->_resourceManager->destroy_buffer(materialBuffer);
fmt::println("[GLTF] clearAll done for '{}' (meshes={}, images={}, materials={}, samplers={})",
name,
meshes.size(),
images.size(),
materials.size(),
samplers.size());
} }

View File

@@ -113,7 +113,13 @@ struct LoadedGLTF : public IRenderable
void setActiveAnimation(int index, bool resetTime = true); void setActiveAnimation(int index, bool resetTime = true);
void setActiveAnimation(const std::string &name, bool resetTime = true); void setActiveAnimation(const std::string &name, bool resetTime = true);
~LoadedGLTF() { clearAll(); }; ~LoadedGLTF()
{
const char *name = debugName.empty() ? "<unnamed>" : debugName.c_str();
fmt::println("[GLTF] ~LoadedGLTF destructor begin for '{}' ({})", name, static_cast<const void *>(this));
clearAll();
fmt::println("[GLTF] ~LoadedGLTF destructor end for '{}' ({})", name, static_cast<const void *>(this));
};
void clearMeshes(){ clearAll(); }; void clearMeshes(){ clearAll(); };

View File

@@ -17,6 +17,15 @@
#include "frame_resources.h" #include "frame_resources.h"
#include "core/config.h" #include "core/config.h"
#include <fmt/core.h>
SceneManager::~SceneManager()
{
fmt::println("[SceneManager] dtor: loadedScenes={} dynamicGLTFInstances={} pendingGLTFRelease={}",
loadedScenes.size(),
dynamicGLTFInstances.size(),
pendingGLTFRelease.size());
}
void SceneManager::init(EngineContext *context) void SceneManager::init(EngineContext *context)
{ {
@@ -41,6 +50,13 @@ void SceneManager::update_scene()
// until the GPU has finished work that might still reference their resources. // until the GPU has finished work that might still reference their resources.
if (_context && _context->currentFrame) if (_context && _context->currentFrame)
{ {
if (!pendingGLTFRelease.empty())
{
fmt::println("[SceneManager] update_scene: scheduling {} pending GLTF releases (hasContext={}, hasFrame={})",
pendingGLTFRelease.size(),
true,
true);
}
for (auto &sp : pendingGLTFRelease) for (auto &sp : pendingGLTFRelease)
{ {
auto keepAlive = sp; // copy to keep ref count in the lambda auto keepAlive = sp; // copy to keep ref count in the lambda
@@ -332,6 +348,9 @@ void SceneManager::addGLTFInstance(const std::string &name, std::shared_ptr<Load
const glm::mat4 &transform) const glm::mat4 &transform)
{ {
if (!scene) return; if (!scene) return;
fmt::println("[SceneManager] addGLTFInstance '{}' (scene='{}')",
name,
scene->debugName.empty() ? "<unnamed>" : scene->debugName.c_str());
dynamicGLTFInstances[name] = GLTFInstance{std::move(scene), transform}; dynamicGLTFInstances[name] = GLTFInstance{std::move(scene), transform};
} }
@@ -346,6 +365,9 @@ bool SceneManager::removeGLTFInstance(const std::string &name)
if (_context && _context->currentFrame) if (_context && _context->currentFrame)
{ {
auto keepAlive = it->second.scene; auto keepAlive = it->second.scene;
fmt::println("[SceneManager] removeGLTFInstance '{}' scheduling deferred destroy (scene='{}')",
name,
keepAlive && !keepAlive->debugName.empty() ? keepAlive->debugName.c_str() : "<unnamed>");
_context->currentFrame->_deletionQueue.push_function([keepAlive]() mutable { keepAlive.reset(); }); _context->currentFrame->_deletionQueue.push_function([keepAlive]() mutable { keepAlive.reset(); });
} }
else else
@@ -369,6 +391,9 @@ bool SceneManager::setGLTFInstanceTransform(const std::string &name, const glm::
void SceneManager::clearGLTFInstances() void SceneManager::clearGLTFInstances()
{ {
fmt::println("[SceneManager] clearGLTFInstances: dynamicGLTFInstances={} pendingBefore={}",
dynamicGLTFInstances.size(),
pendingGLTFRelease.size());
for (auto &kv : dynamicGLTFInstances) for (auto &kv : dynamicGLTFInstances)
{ {
if (kv.second.scene) if (kv.second.scene)
@@ -377,6 +402,8 @@ void SceneManager::clearGLTFInstances()
} }
} }
dynamicGLTFInstances.clear(); dynamicGLTFInstances.clear();
fmt::println("[SceneManager] clearGLTFInstances: pendingAfter={}",
pendingGLTFRelease.size());
} }
bool SceneManager::setSceneAnimation(const std::string &sceneName, int animationIndex, bool resetTime) bool SceneManager::setSceneAnimation(const std::string &sceneName, int animationIndex, bool resetTime)

View File

@@ -55,6 +55,7 @@ struct DrawContext
class SceneManager class SceneManager
{ {
public: public:
~SceneManager();
void init(EngineContext *context); void init(EngineContext *context);
void cleanup(); void cleanup();